Merge branch 'main' into return_of_the_crab
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
9e52359112
18 changed files with 664 additions and 610 deletions
9
.drone.yml
Normal file
9
.drone.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: frontend
|
||||
|
||||
steps:
|
||||
- name: dependencies
|
||||
image: rust:slim
|
||||
commands:
|
||||
- cargo doc
|
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -1103,6 +1103,25 @@ dependencies = [
|
|||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minecrab"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ahash 0.7.4",
|
||||
"anyhow",
|
||||
"bytemuck",
|
||||
"cgmath",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"gltf",
|
||||
"image",
|
||||
"log",
|
||||
"noise",
|
||||
"rayon",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.7"
|
||||
|
@ -1574,25 +1593,6 @@ version = "0.6.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "rustwgpu"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ahash 0.7.4",
|
||||
"anyhow",
|
||||
"bytemuck",
|
||||
"cgmath",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"gltf",
|
||||
"image",
|
||||
"log",
|
||||
"noise",
|
||||
"rayon",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[package]
|
||||
name = "rustwgpu"
|
||||
name = "minecrab"
|
||||
version = "0.1.0"
|
||||
authors = ["Vijfhoek <me@vijf.life>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
101
src/chunk.rs
101
src/chunk.rs
|
@ -1,9 +1,10 @@
|
|||
use std::{collections::VecDeque, convert::TryInto, usize};
|
||||
use std::{collections::VecDeque, usize};
|
||||
|
||||
use crate::{cube, quad::Quad, vertex::Vertex};
|
||||
use crate::{geometry::Geometry, quad::Quad, vertex::BlockVertex};
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use cgmath::{Vector3, Zero};
|
||||
use cgmath::Vector3;
|
||||
use noise::utils::{NoiseMapBuilder, PlaneMapBuilder};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -46,6 +47,8 @@ pub const FACE_BOTTOM: FaceFlags = 4;
|
|||
pub const FACE_TOP: FaceFlags = 8;
|
||||
pub const FACE_BACK: FaceFlags = 16;
|
||||
pub const FACE_FRONT: FaceFlags = 32;
|
||||
pub const FACE_ALL: FaceFlags =
|
||||
FACE_LEFT | FACE_RIGHT | FACE_BOTTOM | FACE_TOP | FACE_BACK | FACE_FRONT;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Block {
|
||||
|
@ -218,12 +221,13 @@ impl Chunk {
|
|||
culled: AHashMap<(usize, usize), (BlockType, FaceFlags)>,
|
||||
queue: &mut VecDeque<(usize, usize)>,
|
||||
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();
|
||||
) -> Vec<Quad> {
|
||||
let mut quads: Vec<Quad> = Vec::new();
|
||||
let mut visited = AHashSet::new();
|
||||
let hl = highlighted.map(|h| h.0);
|
||||
while let Some((x, z)) = queue.pop_front() {
|
||||
let position = offset + Vector3::new(x, y, z).cast().unwrap();
|
||||
|
||||
if visited.contains(&(x, z)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -233,28 +237,19 @@ impl Chunk {
|
|||
let mut quad_faces = visible_faces;
|
||||
|
||||
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,
|
||||
highlighted.unwrap().1,
|
||||
quad_faces,
|
||||
));
|
||||
let mut quad = Quad::new(position, 1, 1);
|
||||
quad.highlighted_normal = highlighted.unwrap().1;
|
||||
quad.visible_faces = quad_faces;
|
||||
quad.block_type = Some(block_type);
|
||||
quads.push(quad);
|
||||
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,
|
||||
Vector3::zero(),
|
||||
quad_faces,
|
||||
));
|
||||
let mut quad = Quad::new(position, 1, 1);
|
||||
quad.visible_faces = quad_faces;
|
||||
quad.block_type = Some(block_type);
|
||||
quads.push(quad);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -304,60 +299,36 @@ 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,
|
||||
Vector3::zero(),
|
||||
quad_faces,
|
||||
));
|
||||
let mut quad = Quad::new(position, (xmax - x) as i32, (zmax - z) as i32);
|
||||
quad.visible_faces = quad_faces;
|
||||
quad.block_type = Some(block_type);
|
||||
quads.push(quad);
|
||||
}
|
||||
}
|
||||
|
||||
quads
|
||||
}
|
||||
|
||||
fn quads_to_geometry(
|
||||
quads: Vec<(BlockType, i32, Vector3<i32>, Quad, Vector3<i32>, FaceFlags)>,
|
||||
) -> (Vec<Vertex>, Vec<u16>) {
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
for (block_type, y, offset, quad, highlighted, visible_faces) in quads {
|
||||
let texture_indices = block_type.texture_indices();
|
||||
|
||||
let (quad_vertices, quad_indices) = &cube::vertices(
|
||||
&quad,
|
||||
y,
|
||||
1.0,
|
||||
offset,
|
||||
texture_indices,
|
||||
highlighted,
|
||||
visible_faces,
|
||||
vertices.len().try_into().unwrap(),
|
||||
);
|
||||
|
||||
vertices.extend(quad_vertices);
|
||||
indices.extend(quad_indices);
|
||||
fn quads_to_geometry(quads: Vec<Quad>) -> Geometry<BlockVertex> {
|
||||
let mut geometry: Geometry<BlockVertex> = Default::default();
|
||||
for quad in quads {
|
||||
geometry.append(&mut quad.to_geometry(geometry.vertices.len() as u16));
|
||||
}
|
||||
|
||||
(vertices, indices)
|
||||
geometry
|
||||
}
|
||||
|
||||
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, highlighted);
|
||||
quads.append(&mut layer_quads);
|
||||
}
|
||||
) -> Geometry<BlockVertex> {
|
||||
let quads: Vec<Quad> = (0..CHUNK_SIZE)
|
||||
.into_par_iter()
|
||||
.flat_map(|y| {
|
||||
let (culled, mut queue) = self.cull_layer(y);
|
||||
self.layer_to_quads(y, offset, culled, &mut queue, highlighted)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self::quads_to_geometry(quads)
|
||||
}
|
||||
|
|
132
src/cube.rs
132
src/cube.rs
|
@ -1,132 +0,0 @@
|
|||
use cgmath::Vector3;
|
||||
|
||||
use crate::{
|
||||
chunk::{FaceFlags, FACE_BACK, FACE_BOTTOM, FACE_FRONT, FACE_LEFT, FACE_RIGHT, FACE_TOP},
|
||||
quad::Quad,
|
||||
vertex::Vertex,
|
||||
};
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
#[rustfmt::skip]
|
||||
pub fn vertices(
|
||||
quad: &Quad,
|
||||
y: i32,
|
||||
z_height: f32,
|
||||
offset: Vector3<i32>,
|
||||
texture_indices: (usize, usize, usize, usize, usize, usize),
|
||||
highlighted: Vector3<i32>,
|
||||
visible_faces: FaceFlags,
|
||||
start_index: u16,
|
||||
) -> (Vec<Vertex>, Vec<u16>) {
|
||||
let w = quad.w as f32;
|
||||
let h = quad.h as f32;
|
||||
let zh = z_height;
|
||||
|
||||
let x = (quad.x + offset.x) as f32;
|
||||
let y = (y + offset.y) as f32;
|
||||
let z = (quad.y + offset.z) as f32;
|
||||
|
||||
let t = texture_indices;
|
||||
|
||||
let mut current_index = start_index;
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
let highlighted: [f32; 3] = (-highlighted).cast().unwrap().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 },
|
||||
Vertex { position: [x, y + zh, z + h], texture_coordinates: [0.0, 0.0, t.0 as f32], normal, highlighted },
|
||||
Vertex { position: [x, y + zh, z ], texture_coordinates: [h, 0.0, t.0 as f32], normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
2 + current_index, current_index, 1 + current_index,
|
||||
3 + current_index, current_index, 2 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
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 },
|
||||
Vertex { position: [x + w, y + zh, z + h], texture_coordinates: [h, 0.0, t.1 as f32], normal, highlighted },
|
||||
Vertex { position: [x + w, y + zh, z ], texture_coordinates: [0.0, 0.0, t.1 as f32], normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
1 + current_index, current_index, 2 + current_index,
|
||||
2 + current_index, current_index, 3 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
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 },
|
||||
Vertex { position: [x + w, y + zh, z], texture_coordinates: [0.0, 0.0, t.2 as f32], normal, highlighted },
|
||||
Vertex { position: [x + w, y, z], texture_coordinates: [0.0, 1.0, t.2 as f32], normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
2 + current_index, current_index, 1 + current_index,
|
||||
3 + current_index, current_index, 2 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
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 },
|
||||
Vertex { position: [x + w, y + zh, z + h], texture_coordinates: [w, 0.0, t.3 as f32], normal, highlighted },
|
||||
Vertex { position: [x + w, y, z + h], texture_coordinates: [w, 1.0, t.3 as f32], normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
1 + current_index, current_index, 2 + current_index,
|
||||
2 + current_index, current_index, 3 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
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 },
|
||||
Vertex { position: [x + w, y, z + h], texture_coordinates: [0.0, h, t.4 as f32], normal, highlighted },
|
||||
Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 0.0, t.4 as f32], normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
current_index, 2 + current_index, 1 + current_index,
|
||||
current_index, 3 + current_index, 2 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
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 },
|
||||
Vertex { position: [x + w, y + zh, z + h], texture_coordinates: [w, h, t.5 as f32], normal, highlighted },
|
||||
Vertex { position: [x + w, y + zh, z ], texture_coordinates: [w, 0.0, t.5 as f32], normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
current_index, 1 + current_index, 2 + current_index,
|
||||
current_index, 2 + current_index, 3 + current_index,
|
||||
]);
|
||||
}
|
||||
|
||||
(vertices, indices)
|
||||
}
|
75
src/geometry.rs
Normal file
75
src/geometry.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use wgpu::{
|
||||
util::{BufferInitDescriptor, DeviceExt},
|
||||
RenderPass,
|
||||
};
|
||||
|
||||
use crate::{render_context::RenderContext, vertex::Vertex};
|
||||
|
||||
/// Represents a set of triangles by its vertices and indices.
|
||||
#[derive(Default)]
|
||||
pub struct Geometry<T: Vertex> {
|
||||
pub vertices: Vec<T>,
|
||||
pub indices: Vec<u16>,
|
||||
}
|
||||
|
||||
impl<T: Vertex> Geometry<T> {
|
||||
pub fn new(vertices: Vec<T>, indices: Vec<u16>) -> Self {
|
||||
Self { vertices, indices }
|
||||
}
|
||||
|
||||
/// Moves all the vertices and indices of `other` into `Self`, leaving `other` empty.
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
self.vertices.append(&mut other.vertices);
|
||||
self.indices.append(&mut other.indices);
|
||||
}
|
||||
|
||||
/// Returns the number of indices in the vertex.
|
||||
pub fn index_count(&self) -> usize {
|
||||
self.indices.len()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GeometryBuffers {
|
||||
pub vertices: wgpu::Buffer,
|
||||
pub indices: wgpu::Buffer,
|
||||
pub index_count: usize,
|
||||
}
|
||||
|
||||
impl GeometryBuffers {
|
||||
pub fn from_geometry<T: Vertex + bytemuck::Pod>(
|
||||
render_context: &RenderContext,
|
||||
geometry: &Geometry<T>,
|
||||
usage: wgpu::BufferUsage,
|
||||
) -> Self {
|
||||
let vertices = render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&geometry.vertices),
|
||||
usage: wgpu::BufferUsage::VERTEX | usage,
|
||||
});
|
||||
|
||||
let indices = render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&geometry.indices),
|
||||
usage: wgpu::BufferUsage::INDEX | usage,
|
||||
});
|
||||
|
||||
Self {
|
||||
vertices,
|
||||
indices,
|
||||
index_count: geometry.index_count(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_buffers<'a>(&'a self, render_pass: &mut RenderPass<'a>) {
|
||||
render_pass.set_vertex_buffer(0, self.vertices.slice(..));
|
||||
render_pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16);
|
||||
}
|
||||
|
||||
pub fn draw_indexed(&self, render_pass: &mut RenderPass) {
|
||||
render_pass.draw_indexed(0..self.index_count as u32, 0, 0..1);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
mod aabb;
|
||||
mod camera;
|
||||
mod chunk;
|
||||
mod cube;
|
||||
mod geometry;
|
||||
mod quad;
|
||||
mod render_context;
|
||||
mod state;
|
||||
mod text_renderer;
|
||||
mod texture;
|
||||
mod time;
|
||||
mod uniforms;
|
||||
mod vertex;
|
||||
mod view;
|
||||
mod world;
|
||||
mod npc;
|
||||
|
||||
|
@ -106,7 +106,7 @@ fn main() {
|
|||
let fps_min = 1_000_000 / frametime_max.as_micros();
|
||||
|
||||
println!(
|
||||
"{:>4} frames | frametime avg={:>5.2}ms min={:>5.2}ms max={:>5.2}ms | fps avg={:>4} min={:>4} max={:>4} | {:>8} tris",
|
||||
"{:>4} frames | frametime avg={:>5.2}ms min={:>5.2}ms max={:>5.2}ms | fps avg={:>5} min={:>5} max={:>5} | {:>8} tris",
|
||||
frames, frametime.as_secs_f32() * 1000.0, frametime_min.as_secs_f32() * 1000.0, frametime_max.as_secs_f32() * 1000.0, fps, fps_min, fps_max, triangle_count,
|
||||
);
|
||||
|
||||
|
|
32
src/npc.rs
32
src/npc.rs
|
@ -1,23 +1,20 @@
|
|||
extern crate gltf;
|
||||
extern crate wgpu;
|
||||
|
||||
use cgmath::{Vector3};
|
||||
use cgmath::Vector3;
|
||||
|
||||
use crate::{
|
||||
vertex::Vertex,
|
||||
};
|
||||
use crate::vertex::BlockVertex;
|
||||
|
||||
pub struct Npc {
|
||||
pub position: Vector3<f32>,
|
||||
pub scale: Vector3<f32>,
|
||||
pub rotation: Vector3<f32>,
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub vertices: Vec<BlockVertex>,
|
||||
pub indices: Vec<u32>,
|
||||
pub vertex_buffer: Option<wgpu::Buffer>,
|
||||
pub index_buffer: Option<wgpu::Buffer>,
|
||||
}
|
||||
|
||||
|
||||
impl Npc {
|
||||
pub fn load() -> Self {
|
||||
let position: Vector3<f32> = Vector3::new(0.0, 0.0, 0.0);
|
||||
|
@ -26,33 +23,34 @@ impl Npc {
|
|||
|
||||
let (model, buffers, _) = gltf::import("assets/models/minecrab.glb").unwrap();
|
||||
|
||||
let mut indices: Vec<u32> = Vec::new();
|
||||
let mut vertices: Vec<Vertex> = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
let mut vertices = Vec::new();
|
||||
|
||||
for mesh in model.meshes() {
|
||||
for primitive in mesh.primitives() {
|
||||
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
|
||||
indices = reader.read_indices().unwrap().into_u32().collect();
|
||||
// loop over all primitives and get the normals, position and color
|
||||
|
||||
// loop over all primitives and get the normals, position and color
|
||||
let pos_iter = reader.read_positions().unwrap();
|
||||
let norm_iter = reader.read_normals().unwrap();
|
||||
let tex_iter = reader.read_tex_coords(0).unwrap().into_f32();
|
||||
|
||||
for it in pos_iter.zip(norm_iter).zip(tex_iter) {
|
||||
let ((position, normal), [tex_x, tex_y]) = it;
|
||||
|
||||
let current_vert: Vertex = Vertex {
|
||||
for ((position, normal), texture_coordinates) in
|
||||
pos_iter.zip(norm_iter).zip(tex_iter)
|
||||
{
|
||||
let current_vert = BlockVertex {
|
||||
position,
|
||||
texture_coordinates: [tex_x, tex_y, 0.0],
|
||||
texture_coordinates,
|
||||
normal,
|
||||
highlighted: 0
|
||||
highlighted: 0,
|
||||
texture_id: 0,
|
||||
};
|
||||
|
||||
vertices.push(current_vert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Self {
|
||||
position,
|
||||
|
@ -61,7 +59,7 @@ impl Npc {
|
|||
indices,
|
||||
vertices,
|
||||
vertex_buffer: None,
|
||||
index_buffer: None
|
||||
index_buffer: None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
170
src/quad.rs
170
src/quad.rs
|
@ -1,13 +1,171 @@
|
|||
use cgmath::{Vector3, Zero};
|
||||
|
||||
use crate::{
|
||||
chunk::{
|
||||
BlockType, FaceFlags, FACE_ALL, FACE_BACK, FACE_BOTTOM, FACE_FRONT, FACE_LEFT, FACE_RIGHT,
|
||||
FACE_TOP,
|
||||
},
|
||||
geometry::Geometry,
|
||||
vertex::BlockVertex,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Quad {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub w: i32,
|
||||
pub h: i32,
|
||||
pub position: Vector3<i32>,
|
||||
pub dx: i32,
|
||||
pub dz: i32,
|
||||
|
||||
pub highlighted_normal: Vector3<i32>,
|
||||
pub visible_faces: FaceFlags,
|
||||
pub block_type: Option<BlockType>,
|
||||
}
|
||||
|
||||
impl Quad {
|
||||
pub fn new(x: i32, y: i32, w: i32, h: i32) -> Self {
|
||||
Quad { x, y, w, h }
|
||||
pub fn new(position: Vector3<i32>, dx: i32, dz: i32) -> Self {
|
||||
Quad {
|
||||
position,
|
||||
dx,
|
||||
dz,
|
||||
|
||||
/// The normal of the face that was highlighted.
|
||||
///
|
||||
/// Set to Vector3::zero if no faces are highlighted.
|
||||
highlighted_normal: Vector3::zero(),
|
||||
|
||||
/// Bitmap of the visible faces.
|
||||
visible_faces: FACE_ALL,
|
||||
|
||||
/// The `BlockType` of the blocks the quad describes.
|
||||
///
|
||||
/// Used for determining which texture to map to it. When `None`, texture index 0 will be used.
|
||||
block_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the quad to `Geometry` (i.e. a list of vertices and indices) to be rendered.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `start_index` - Which geometry index to start at.
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
#[rustfmt::skip]
|
||||
pub fn to_geometry(
|
||||
&self,
|
||||
start_index: u16,
|
||||
) -> Geometry<BlockVertex> {
|
||||
let dx = self.dx as f32;
|
||||
let dz = self.dz as f32;
|
||||
let dy = 1.0;
|
||||
|
||||
let x = self.position.x as f32;
|
||||
let y = self.position.y as f32;
|
||||
let z = self.position.z as f32;
|
||||
|
||||
let t = match self.block_type {
|
||||
Some(block_type) => block_type.texture_indices(),
|
||||
None => (0, 0, 0, 0, 0, 0),
|
||||
};
|
||||
|
||||
let mut current_index = start_index;
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
let highlighted: [f32; 3] = self.highlighted_normal.cast().unwrap().into();
|
||||
|
||||
if self.visible_faces & FACE_LEFT == FACE_LEFT {
|
||||
let normal = [-1.0, 0.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
BlockVertex { position: [x, y, z ], texture_coordinates: [dz, 1.0], texture_id: t.0 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y, z + dz], texture_coordinates: [0.0, 1.0], texture_id: t.0 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y + dy, z + dz], texture_coordinates: [0.0, 0.0], texture_id: t.0 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y + dy, z ], texture_coordinates: [dz, 0.0], texture_id: t.0 as i32, normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
2 + current_index, current_index, 1 + current_index,
|
||||
3 + current_index, current_index, 2 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
if self.visible_faces & FACE_RIGHT == FACE_RIGHT {
|
||||
let normal = [1.0, 0.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
BlockVertex { position: [x + dx, y, z ], texture_coordinates: [0.0, 1.0], texture_id: t.1 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y, z + dz], texture_coordinates: [dz, 1.0], texture_id: t.1 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y + dy, z + dz], texture_coordinates: [dz, 0.0], texture_id: t.1 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y + dy, z ], texture_coordinates: [0.0, 0.0], texture_id: t.1 as i32, normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
1 + current_index, current_index, 2 + current_index,
|
||||
2 + current_index, current_index, 3 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
if self.visible_faces & FACE_BACK == FACE_BACK {
|
||||
let normal = [0.0, 0.0, -1.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
BlockVertex { position: [x, y, z], texture_coordinates: [dx, 1.0], texture_id: t.2 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y + dy, z], texture_coordinates: [dx, 0.0], texture_id: t.2 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y + dy, z], texture_coordinates: [0.0, 0.0], texture_id: t.2 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y, z], texture_coordinates: [0.0, 1.0], texture_id: t.2 as i32, normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
2 + current_index, current_index, 1 + current_index,
|
||||
3 + current_index, current_index, 2 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
if self.visible_faces & FACE_FRONT == FACE_FRONT {
|
||||
let normal = [0.0, 0.0, 1.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
BlockVertex { position: [x, y, z + dz], texture_coordinates: [0.0, 1.0], texture_id: t.3 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y + dy, z + dz], texture_coordinates: [0.0, 0.0], texture_id: t.3 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y + dy, z + dz], texture_coordinates: [dx, 0.0], texture_id: t.3 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y, z + dz], texture_coordinates: [dx, 1.0], texture_id: t.3 as i32, normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
1 + current_index, current_index, 2 + current_index,
|
||||
2 + current_index, current_index, 3 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
if self.visible_faces & FACE_BOTTOM == FACE_BOTTOM {
|
||||
let normal = [0.0, -1.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
BlockVertex { position: [x, y, z ], texture_coordinates: [dx, 0.0], texture_id: t.4 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y, z + dz], texture_coordinates: [dx, dz ], texture_id: t.4 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y, z + dz], texture_coordinates: [0.0, dz ], texture_id: t.4 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y, z ], texture_coordinates: [0.0, 0.0], texture_id: t.4 as i32, normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
current_index, 2 + current_index, 1 + current_index,
|
||||
current_index, 3 + current_index, 2 + current_index,
|
||||
]);
|
||||
current_index += 4;
|
||||
}
|
||||
|
||||
if self.visible_faces & FACE_TOP == FACE_TOP {
|
||||
let normal = [0.0, 1.0, 0.0];
|
||||
let highlighted = (normal == highlighted) as i32;
|
||||
vertices.extend(&[
|
||||
BlockVertex { position: [x, y + dy, z ], texture_coordinates: [0.0, 0.0], texture_id: t.5 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x, y + dy, z + dz], texture_coordinates: [0.0, dz ], texture_id: t.5 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y + dy, z + dz], texture_coordinates: [dx, dz ], texture_id: t.5 as i32, normal, highlighted },
|
||||
BlockVertex { position: [x + dx, y + dy, z ], texture_coordinates: [dx, 0.0], texture_id: t.5 as i32, normal, highlighted },
|
||||
]);
|
||||
indices.extend(&[
|
||||
current_index, 1 + current_index, 2 + current_index,
|
||||
current_index, 2 + current_index, 3 + current_index,
|
||||
]);
|
||||
}
|
||||
|
||||
Geometry::new(vertices, indices)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
struct VertexInput {
|
||||
[[location(0)]] position: vec3<f32>;
|
||||
[[location(0)]] position: vec2<f32>;
|
||||
[[location(1)]] texture_coordinates: vec2<f32>;
|
||||
[[location(2)]] normal: vec3<f32>;
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
|
@ -13,7 +12,7 @@ struct VertexOutput {
|
|||
fn main(model: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.texture_coordinates = model.texture_coordinates;
|
||||
out.clip_position = vec4<f32>(model.position, 1.0);
|
||||
out.clip_position = vec4<f32>(model.position, 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[[block]]
|
||||
struct Uniforms {
|
||||
view_position: vec4<f32>;
|
||||
view_projection: mat4x4<f32>;
|
||||
struct View {
|
||||
position: vec4<f32>;
|
||||
projection: mat4x4<f32>;
|
||||
};
|
||||
|
||||
[[block]]
|
||||
|
@ -10,24 +10,26 @@ struct Time {
|
|||
};
|
||||
|
||||
[[group(1), binding(0)]]
|
||||
var<uniform> uniforms: Uniforms;
|
||||
var<uniform> view: View;
|
||||
|
||||
[[group(2), binding(0)]]
|
||||
var<uniform> time: Time;
|
||||
|
||||
struct VertexInput {
|
||||
[[location(0)]] position: vec3<f32>;
|
||||
[[location(1)]] texture_coordinates: vec3<f32>;
|
||||
[[location(1)]] texture_coordinates: vec2<f32>;
|
||||
[[location(2)]] normal: vec3<f32>;
|
||||
[[location(3)]] highlighted: i32;
|
||||
[[location(4)]] texture_id: i32;
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
[[builtin(position)]] clip_position: vec4<f32>;
|
||||
[[location(0)]] texture_coordinates: vec3<f32>;
|
||||
[[location(0)]] texture_coordinates: vec2<f32>;
|
||||
[[location(1)]] world_normal: vec3<f32>;
|
||||
[[location(2)]] world_position: vec3<f32>;
|
||||
[[location(3)]] highlighted: i32;
|
||||
[[location(4)]] texture_id: i32;
|
||||
};
|
||||
|
||||
let pi: f32 = 3.14159265359;
|
||||
|
@ -37,17 +39,19 @@ fn main(model: VertexInput) -> VertexOutput {
|
|||
var out: VertexOutput;
|
||||
|
||||
out.world_normal = model.normal;
|
||||
if (model.texture_coordinates.z == 8.0) {
|
||||
if (model.texture_id == 8) {
|
||||
// water
|
||||
let offset = (sin(time.time * 0.5 + model.position.x) * cos(time.time * 0.9 + model.position.y) + 2.5) / 10.0;
|
||||
out.world_position = vec3<f32>(model.position.x, model.position.y - offset, model.position.z);
|
||||
out.texture_coordinates = vec3<f32>(model.texture_coordinates.xy + (time.time / 10.0), 8.0 + (time.time * 10.0) % 32.0);
|
||||
out.texture_coordinates = model.texture_coordinates + (time.time / 10.0);
|
||||
out.texture_id = i32(8.0 + (time.time * 10.0) % 32.0);
|
||||
} else {
|
||||
out.world_position = model.position;
|
||||
out.texture_coordinates = model.texture_coordinates;
|
||||
out.texture_id = model.texture_id;
|
||||
}
|
||||
|
||||
out.clip_position = uniforms.view_projection * vec4<f32>(out.world_position, 1.0);
|
||||
out.clip_position = view.projection * vec4<f32>(out.world_position, 1.0);
|
||||
out.highlighted = model.highlighted;
|
||||
return out;
|
||||
}
|
||||
|
@ -60,8 +64,8 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
|||
let object_color: vec4<f32> = textureSample(
|
||||
texture_array,
|
||||
texture_sampler,
|
||||
in.texture_coordinates.xy,
|
||||
i32(round(in.texture_coordinates.z))
|
||||
in.texture_coordinates,
|
||||
in.texture_id
|
||||
);
|
||||
|
||||
let light_position = vec3<f32>(-100.0, 500.0, -200.0);
|
||||
|
@ -71,7 +75,7 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
|||
let ambient_color = light_color * ambient_strength;
|
||||
|
||||
let light_direction = normalize(light_position - in.world_position);
|
||||
let view_direction = normalize(uniforms.view_position.xyz - in.world_position);
|
||||
let view_direction = normalize(view.position.xyz - in.world_position);
|
||||
let half_direction = normalize(view_direction + light_direction);
|
||||
|
||||
let diffuse_strength = max(dot(in.world_normal, light_direction), 0.0);
|
||||
|
|
|
@ -1,40 +1,36 @@
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
use cgmath::Vector3;
|
||||
use wgpu::{
|
||||
util::{BufferInitDescriptor, DeviceExt},
|
||||
CommandEncoder, SwapChainTexture,
|
||||
};
|
||||
use wgpu::{BufferUsage, CommandEncoder, SwapChainTexture};
|
||||
|
||||
use crate::{
|
||||
geometry::{Geometry, GeometryBuffers},
|
||||
render_context::RenderContext,
|
||||
state::PRIMITIVE_STATE,
|
||||
text_renderer::{self, TextRenderer},
|
||||
texture::Texture,
|
||||
vertex::Vertex,
|
||||
vertex::{HudVertex, Vertex},
|
||||
};
|
||||
|
||||
// TODO update aspect ratio when resizing
|
||||
const UI_SCALE_X: f32 = 0.0045;
|
||||
const UI_SCALE_Y: f32 = 0.008;
|
||||
|
||||
pub struct HudState {
|
||||
texture_bind_group: wgpu::BindGroup,
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
crosshair_vertex_buffer: wgpu::Buffer,
|
||||
crosshair_index_buffer: wgpu::Buffer,
|
||||
hud_geometry_buffers: GeometryBuffers,
|
||||
|
||||
text_renderer: TextRenderer,
|
||||
|
||||
fps_vertex_buffer: wgpu::Buffer,
|
||||
fps_index_buffer: wgpu::Buffer,
|
||||
fps_index_count: usize,
|
||||
fps_geometry_buffers: GeometryBuffers,
|
||||
fps_instant: Instant,
|
||||
fps_frames: u32,
|
||||
fps_elapsed: Duration,
|
||||
|
||||
coordinates_vertex_buffer: wgpu::Buffer,
|
||||
coordinates_index_buffer: wgpu::Buffer,
|
||||
coordinates_index_count: usize,
|
||||
coordinates_geometry_buffers: GeometryBuffers,
|
||||
coordinates_last: Vector3<f32>,
|
||||
pub hotbar_cursor_position: i32,
|
||||
}
|
||||
|
||||
impl HudState {
|
||||
|
@ -44,48 +40,37 @@ impl HudState {
|
|||
let render_pipeline =
|
||||
Self::create_render_pipeline(render_context, &[&texture_bind_group_layout]);
|
||||
|
||||
let crosshair_vertex_buffer =
|
||||
render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("HUD crosshair vertex buffer"),
|
||||
contents: bytemuck::cast_slice(&CROSSHAIR_VERTICES),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
});
|
||||
|
||||
let crosshair_index_buffer =
|
||||
render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("HUD crosshair index buffer"),
|
||||
contents: bytemuck::cast_slice(CROSSHAIR_INDICES),
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
});
|
||||
// HUD buffers
|
||||
let hud_geometry = Geometry {
|
||||
vertices: HUD_VERTICES.to_vec(),
|
||||
indices: HUD_INDICES.to_vec(),
|
||||
};
|
||||
let hud_geometry_buffers =
|
||||
GeometryBuffers::from_geometry(render_context, &hud_geometry, BufferUsage::COPY_DST);
|
||||
|
||||
// Text buffers
|
||||
let text_renderer = TextRenderer::new(render_context).unwrap();
|
||||
let (fps_vertex_buffer, fps_index_buffer, fps_index_count) =
|
||||
let fps_geometry_buffers =
|
||||
text_renderer.string_to_buffers(&render_context, -0.98, 0.97, "");
|
||||
let (coordinates_vertex_buffer, coordinates_index_buffer, coordinates_index_count) =
|
||||
let coordinates_geometry_buffers =
|
||||
text_renderer.string_to_buffers(&render_context, -0.98, 0.97 - text_renderer::DY, "");
|
||||
|
||||
Self {
|
||||
texture_bind_group,
|
||||
render_pipeline,
|
||||
crosshair_vertex_buffer,
|
||||
crosshair_index_buffer,
|
||||
text_renderer,
|
||||
|
||||
fps_vertex_buffer,
|
||||
fps_index_buffer,
|
||||
fps_index_count,
|
||||
hud_geometry_buffers,
|
||||
|
||||
fps_geometry_buffers,
|
||||
fps_instant: Instant::now(),
|
||||
fps_frames: 0,
|
||||
fps_elapsed: Duration::from_secs(0),
|
||||
|
||||
coordinates_vertex_buffer,
|
||||
coordinates_index_buffer,
|
||||
coordinates_index_count,
|
||||
coordinates_geometry_buffers,
|
||||
coordinates_last: Vector3::new(0.0, 0.0, 0.0),
|
||||
|
||||
hotbar_cursor_position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,12 +85,9 @@ impl HudState {
|
|||
let fps = 1.0 / frametime.as_secs_f32();
|
||||
|
||||
let string = format!("{:<5.0} fps", fps);
|
||||
let (vertices, indices, index_count) =
|
||||
self.fps_geometry_buffers =
|
||||
self.text_renderer
|
||||
.string_to_buffers(render_context, -0.98, 0.97, &string);
|
||||
self.fps_vertex_buffer = vertices;
|
||||
self.fps_index_buffer = indices;
|
||||
self.fps_index_count = index_count;
|
||||
|
||||
self.fps_elapsed = Duration::from_secs(0);
|
||||
self.fps_frames = 0;
|
||||
|
@ -113,15 +95,12 @@ impl HudState {
|
|||
|
||||
if position != &self.coordinates_last {
|
||||
let string = format!("({:.1},{:.1},{:.1})", position.x, position.y, position.z,);
|
||||
let (vertices, indices, index_count) = self.text_renderer.string_to_buffers(
|
||||
self.coordinates_geometry_buffers = self.text_renderer.string_to_buffers(
|
||||
render_context,
|
||||
-0.98,
|
||||
0.97 - text_renderer::DY * 1.3,
|
||||
&string,
|
||||
);
|
||||
self.coordinates_vertex_buffer = vertices;
|
||||
self.coordinates_index_buffer = indices;
|
||||
self.coordinates_index_count = index_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +110,6 @@ impl HudState {
|
|||
render_encoder: &mut CommandEncoder,
|
||||
) -> anyhow::Result<usize> {
|
||||
let mut render_pass = render_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("render_pass"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||
view: &frame.view,
|
||||
resolve_target: None,
|
||||
|
@ -140,33 +118,58 @@ impl HudState {
|
|||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&self.render_pipeline);
|
||||
render_pass.set_vertex_buffer(0, self.crosshair_vertex_buffer.slice(..));
|
||||
render_pass.set_index_buffer(
|
||||
self.crosshair_index_buffer.slice(..),
|
||||
wgpu::IndexFormat::Uint16,
|
||||
);
|
||||
|
||||
// Render the HUD elements
|
||||
self.hud_geometry_buffers.set_buffers(&mut render_pass);
|
||||
render_pass.set_bind_group(0, &self.texture_bind_group, &[]);
|
||||
render_pass.draw_indexed(0..CROSSHAIR_INDICES.len() as u32, 0, 0..1);
|
||||
self.hud_geometry_buffers.draw_indexed(&mut render_pass);
|
||||
render_pass.draw_indexed(0..self.hud_geometry_buffers.index_count as u32, 0, 0..1);
|
||||
|
||||
render_pass.set_vertex_buffer(0, self.fps_vertex_buffer.slice(..));
|
||||
render_pass.set_index_buffer(self.fps_index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||
// Render the FPS text
|
||||
self.fps_geometry_buffers.set_buffers(&mut render_pass);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
render_pass.draw_indexed(0..self.fps_index_count as u32, 0, 0..1);
|
||||
self.fps_geometry_buffers.draw_indexed(&mut render_pass);
|
||||
|
||||
render_pass.set_vertex_buffer(0, self.coordinates_vertex_buffer.slice(..));
|
||||
render_pass.set_index_buffer(
|
||||
self.coordinates_index_buffer.slice(..),
|
||||
wgpu::IndexFormat::Uint16,
|
||||
// Render the coordinates text
|
||||
self.coordinates_geometry_buffers
|
||||
.set_buffers(&mut render_pass);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
self.coordinates_geometry_buffers
|
||||
.draw_indexed(&mut render_pass);
|
||||
|
||||
Ok(HUD_INDICES.len() / 3)
|
||||
}
|
||||
|
||||
pub fn redraw_hotbar_cursor(&self, render_context: &RenderContext) {
|
||||
let x = (-92 + 20 * self.hotbar_cursor_position) as f32;
|
||||
|
||||
#[rustfmt::skip]
|
||||
let vertices = [
|
||||
HudVertex { position: [UI_SCALE_X * (x ), -1.0 + UI_SCALE_Y * 23.0], texture_coordinates: [ 0.0 / 256.0, 22.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 24.0), -1.0 + UI_SCALE_Y * 23.0], texture_coordinates: [ 24.0 / 256.0, 22.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 24.0), -1.0 + UI_SCALE_Y * -1.0], texture_coordinates: [ 24.0 / 256.0, 46.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * (x ), -1.0 + UI_SCALE_Y * -1.0], texture_coordinates: [ 0.0 / 256.0, 46.0 / 256.0] },
|
||||
];
|
||||
|
||||
render_context.queue.write_buffer(
|
||||
&self.hud_geometry_buffers.vertices,
|
||||
HudVertex::descriptor().array_stride * 8,
|
||||
bytemuck::cast_slice(&vertices),
|
||||
);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
render_pass.draw_indexed(0..self.coordinates_index_count as u32, 0, 0..1);
|
||||
}
|
||||
|
||||
Ok(CROSSHAIR_INDICES.len() / 3)
|
||||
pub fn set_hotbar_cursor(&mut self, render_context: &RenderContext, i: i32) {
|
||||
self.hotbar_cursor_position = i;
|
||||
self.redraw_hotbar_cursor(render_context);
|
||||
}
|
||||
|
||||
pub fn move_hotbar_cursor(&mut self, render_context: &RenderContext, delta: i32) {
|
||||
self.hotbar_cursor_position = (self.hotbar_cursor_position + delta).rem_euclid(9);
|
||||
self.redraw_hotbar_cursor(render_context);
|
||||
}
|
||||
|
||||
fn create_textures(render_context: &RenderContext) -> (wgpu::BindGroupLayout, wgpu::BindGroup) {
|
||||
|
@ -262,7 +265,7 @@ impl HudState {
|
|||
vertex: wgpu::VertexState {
|
||||
module,
|
||||
entry_point: "main",
|
||||
buffers: &[Vertex::desc()],
|
||||
buffers: &[HudVertex::descriptor()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module,
|
||||
|
@ -273,83 +276,45 @@ impl HudState {
|
|||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
clamp_depth: false,
|
||||
conservative: false,
|
||||
},
|
||||
primitive: PRIMITIVE_STATE,
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multisample: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub const CROSSHAIR_VERTICES: &[Vertex] = &[
|
||||
#[rustfmt::skip]
|
||||
pub const HUD_VERTICES: [HudVertex; 12] = [
|
||||
// Crosshair
|
||||
Vertex {
|
||||
position: [-UI_SCALE_X * 8.0, UI_SCALE_Y * 8.0, 0.0],
|
||||
texture_coordinates: [240.0 / 256.0, 0.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
Vertex {
|
||||
position: [UI_SCALE_X * 8.0, UI_SCALE_Y * 8.0, 0.0],
|
||||
texture_coordinates: [1.0, 0.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
Vertex {
|
||||
position: [UI_SCALE_X * 8.0, -UI_SCALE_Y * 8.0, 0.0],
|
||||
texture_coordinates: [1.0, 16.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
Vertex {
|
||||
position: [-UI_SCALE_X * 8.0, -UI_SCALE_Y * 8.0, 0.0],
|
||||
texture_coordinates: [240.0 / 256.0, 16.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
HudVertex { position: [UI_SCALE_X * -8.0, UI_SCALE_Y * 8.0], texture_coordinates: [240.0 / 256.0, 0.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * 8.0, UI_SCALE_Y * 8.0], texture_coordinates: [256.0 / 256.0, 0.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * 8.0, UI_SCALE_Y * -8.0], texture_coordinates: [256.0 / 256.0, 16.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * -8.0, UI_SCALE_Y * -8.0], texture_coordinates: [240.0 / 256.0, 16.0 / 256.0] },
|
||||
|
||||
// Hotbar
|
||||
Vertex {
|
||||
position: [-UI_SCALE_X * 91.0, -1.0 + UI_SCALE_Y * 22.0, 0.0],
|
||||
texture_coordinates: [0.0 / 256.0, 0.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
Vertex {
|
||||
position: [UI_SCALE_X * 91.0, -1.0 + UI_SCALE_Y * 22.0, 0.0],
|
||||
texture_coordinates: [182.0 / 256.0, 0.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
Vertex {
|
||||
position: [UI_SCALE_X * 91.0, -1.0, 0.0],
|
||||
texture_coordinates: [182.0 / 256.0, 22.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
Vertex {
|
||||
position: [-UI_SCALE_X * 91.0, -1.0, 0.0],
|
||||
texture_coordinates: [0.0 / 256.0, 22.0 / 256.0, 0.0],
|
||||
normal: [0.0, 0.0, 0.0],
|
||||
highlighted: 0,
|
||||
},
|
||||
HudVertex { position: [UI_SCALE_X * -91.0, -1.0 + UI_SCALE_Y * 22.0], texture_coordinates: [ 0.0 / 256.0, 0.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * 91.0, -1.0 + UI_SCALE_Y * 22.0], texture_coordinates: [182.0 / 256.0, 0.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * 91.0, -1.0 ], texture_coordinates: [182.0 / 256.0, 22.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * -91.0, -1.0 ], texture_coordinates: [ 0.0 / 256.0, 22.0 / 256.0] },
|
||||
|
||||
// Hotbar cursor
|
||||
HudVertex { position: [UI_SCALE_X * -92.0, -1.0 + UI_SCALE_Y * 23.0], texture_coordinates: [ 0.0 / 256.0, 22.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * -68.0, -1.0 + UI_SCALE_Y * 23.0], texture_coordinates: [ 24.0 / 256.0, 22.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * -68.0, -1.0 + UI_SCALE_Y * -1.0], texture_coordinates: [ 24.0 / 256.0, 46.0 / 256.0] },
|
||||
HudVertex { position: [UI_SCALE_X * -92.0, -1.0 + UI_SCALE_Y * -1.0], texture_coordinates: [ 0.0 / 256.0, 46.0 / 256.0] },
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const CROSSHAIR_INDICES: &[u16] = &[
|
||||
pub const HUD_INDICES: [u16; 18] = [
|
||||
// Crosshair
|
||||
1, 0, 3,
|
||||
1, 3, 2,
|
||||
|
||||
// Hotbar
|
||||
5, 4, 7,
|
||||
5, 7, 6,
|
||||
|
||||
// Hotbar cursor
|
||||
9, 8, 11,
|
||||
9, 11, 10,
|
||||
];
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::time::Duration;
|
|||
use cgmath::EuclideanSpace;
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
event::{DeviceEvent, ElementState, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||
event::{DeviceEvent, ElementState, MouseScrollDelta, VirtualKeyCode, WindowEvent},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,16 @@ use world_state::WorldState;
|
|||
|
||||
use crate::render_context::RenderContext;
|
||||
|
||||
pub const PRIMITIVE_STATE: wgpu::PrimitiveState = wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
clamp_depth: false,
|
||||
conservative: false,
|
||||
};
|
||||
|
||||
pub struct State {
|
||||
pub window_size: PhysicalSize<u32>,
|
||||
render_context: RenderContext,
|
||||
|
@ -122,12 +132,23 @@ impl State {
|
|||
);
|
||||
}
|
||||
|
||||
fn input_keyboard(&mut self, key_code: &VirtualKeyCode, state: &ElementState) {
|
||||
match key_code {
|
||||
VirtualKeyCode::F1 if state == &ElementState::Pressed => {
|
||||
self.world_state.toggle_wireframe(&self.render_context)
|
||||
fn input_keyboard(&mut self, key_code: VirtualKeyCode, state: ElementState) {
|
||||
if state == ElementState::Pressed {
|
||||
match key_code {
|
||||
VirtualKeyCode::F1 => self.world_state.toggle_wireframe(&self.render_context),
|
||||
VirtualKeyCode::Key1 => self.hud_state.set_hotbar_cursor(&self.render_context, 0),
|
||||
VirtualKeyCode::Key2 => self.hud_state.set_hotbar_cursor(&self.render_context, 1),
|
||||
VirtualKeyCode::Key3 => self.hud_state.set_hotbar_cursor(&self.render_context, 2),
|
||||
VirtualKeyCode::Key4 => self.hud_state.set_hotbar_cursor(&self.render_context, 3),
|
||||
VirtualKeyCode::Key5 => self.hud_state.set_hotbar_cursor(&self.render_context, 4),
|
||||
VirtualKeyCode::Key6 => self.hud_state.set_hotbar_cursor(&self.render_context, 5),
|
||||
VirtualKeyCode::Key7 => self.hud_state.set_hotbar_cursor(&self.render_context, 6),
|
||||
VirtualKeyCode::Key8 => self.hud_state.set_hotbar_cursor(&self.render_context, 7),
|
||||
VirtualKeyCode::Key9 => self.hud_state.set_hotbar_cursor(&self.render_context, 8),
|
||||
_ => self.world_state.input_keyboard(key_code, state),
|
||||
}
|
||||
_ => self.world_state.input_keyboard(key_code, state),
|
||||
} else {
|
||||
self.world_state.input_keyboard(key_code, state)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,15 +160,9 @@ impl State {
|
|||
|
||||
pub fn window_event(&mut self, event: &WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(key),
|
||||
state,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => self.input_keyboard(key, state),
|
||||
WindowEvent::KeyboardInput { input, .. } if input.virtual_keycode.is_some() => {
|
||||
self.input_keyboard(input.virtual_keycode.unwrap(), input.state)
|
||||
}
|
||||
|
||||
WindowEvent::MouseInput {
|
||||
button,
|
||||
|
@ -157,14 +172,20 @@ impl State {
|
|||
.world_state
|
||||
.input_mouse_button(button, &self.render_context),
|
||||
|
||||
WindowEvent::MouseWheel {
|
||||
delta: MouseScrollDelta::LineDelta(_, delta),
|
||||
..
|
||||
} => self
|
||||
.hud_state
|
||||
.move_hotbar_cursor(&self.render_context, -*delta as i32),
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device_event(&mut self, event: &DeviceEvent) {
|
||||
match event {
|
||||
DeviceEvent::MouseMotion { delta: (dx, dy) } => self.input_mouse(*dx, *dy),
|
||||
_ => (),
|
||||
if let DeviceEvent::MouseMotion { delta } = event {
|
||||
self.input_mouse(delta.0, delta.1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use ahash::AHashMap;
|
|||
use cgmath::{EuclideanSpace, InnerSpace, Point3, Rad, Vector2, Vector3};
|
||||
use wgpu::{
|
||||
util::{BufferInitDescriptor, DeviceExt},
|
||||
CommandEncoder, SwapChainTexture,
|
||||
BufferUsage, CommandEncoder, SwapChainTexture,
|
||||
};
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
|
@ -14,19 +14,20 @@ use winit::{
|
|||
use crate::{
|
||||
camera::{Camera, Projection},
|
||||
chunk::{Block, BlockType, CHUNK_SIZE},
|
||||
geometry::GeometryBuffers,
|
||||
render_context::RenderContext,
|
||||
texture::{Texture, TextureManager},
|
||||
time::Time,
|
||||
uniforms::Uniforms,
|
||||
vertex::Vertex,
|
||||
vertex::{BlockVertex, Vertex},
|
||||
view::View,
|
||||
world::World,
|
||||
};
|
||||
|
||||
pub struct WorldState {
|
||||
pub render_pipeline: wgpu::RenderPipeline,
|
||||
pub uniforms: Uniforms,
|
||||
pub uniform_buffer: wgpu::Buffer,
|
||||
pub uniform_bind_group: wgpu::BindGroup,
|
||||
pub view: View,
|
||||
pub view_buffer: wgpu::Buffer,
|
||||
pub view_bind_group: wgpu::BindGroup,
|
||||
pub texture_manager: TextureManager,
|
||||
pub camera: Camera,
|
||||
pub projection: Projection,
|
||||
|
@ -34,7 +35,7 @@ pub struct WorldState {
|
|||
pub time_bind_group: wgpu::BindGroup,
|
||||
pub world: World,
|
||||
|
||||
pub chunk_buffers: AHashMap<Vector3<usize>, (wgpu::Buffer, wgpu::Buffer, usize)>,
|
||||
pub chunk_buffers: AHashMap<Vector3<usize>, GeometryBuffers>,
|
||||
time: Time,
|
||||
time_buffer: wgpu::Buffer,
|
||||
wireframe: bool,
|
||||
|
@ -77,28 +78,23 @@ impl WorldState {
|
|||
(camera, projection)
|
||||
}
|
||||
|
||||
fn create_uniforms(
|
||||
fn create_view(
|
||||
camera: &Camera,
|
||||
projection: &Projection,
|
||||
render_context: &RenderContext,
|
||||
) -> (
|
||||
Uniforms,
|
||||
wgpu::Buffer,
|
||||
wgpu::BindGroupLayout,
|
||||
wgpu::BindGroup,
|
||||
) {
|
||||
let mut uniforms = Uniforms::new();
|
||||
uniforms.update_view_projection(camera, projection);
|
||||
) -> (View, wgpu::Buffer, wgpu::BindGroupLayout, wgpu::BindGroup) {
|
||||
let mut view = View::new();
|
||||
view.update_view_projection(camera, projection);
|
||||
|
||||
let uniform_buffer = render_context
|
||||
let view_buffer = render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("uniform_buffer"),
|
||||
contents: bytemuck::cast_slice(&[uniforms]),
|
||||
label: Some("view_buffer"),
|
||||
contents: bytemuck::cast_slice(&[view]),
|
||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
});
|
||||
|
||||
let uniform_bind_group_layout =
|
||||
let view_bind_group_layout =
|
||||
render_context
|
||||
.device
|
||||
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
|
@ -112,27 +108,21 @@ impl WorldState {
|
|||
},
|
||||
count: None,
|
||||
}],
|
||||
label: Some("uniform_bind_group_layout"),
|
||||
label: Some("view_bind_group_layout"),
|
||||
});
|
||||
|
||||
let uniform_bind_group =
|
||||
render_context
|
||||
.device
|
||||
.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &uniform_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform_buffer.as_entire_binding(),
|
||||
}],
|
||||
label: Some("uniform_bind_group"),
|
||||
});
|
||||
let view_bind_group = render_context
|
||||
.device
|
||||
.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &view_bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: view_buffer.as_entire_binding(),
|
||||
}],
|
||||
label: Some("view_bind_group"),
|
||||
});
|
||||
|
||||
(
|
||||
uniforms,
|
||||
uniform_buffer,
|
||||
uniform_bind_group_layout,
|
||||
uniform_bind_group,
|
||||
)
|
||||
(view, view_buffer, view_bind_group_layout, view_bind_group)
|
||||
}
|
||||
|
||||
fn create_time(
|
||||
|
@ -193,7 +183,7 @@ impl WorldState {
|
|||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "main",
|
||||
buffers: &[Vertex::desc()],
|
||||
buffers: &[BlockVertex::descriptor()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
|
@ -232,52 +222,35 @@ impl WorldState {
|
|||
|
||||
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(
|
||||
chunk_position,
|
||||
(
|
||||
render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&chunk_vertices),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
}),
|
||||
render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&chunk_indices),
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
}),
|
||||
chunk_indices.len(),
|
||||
),
|
||||
for (chunk_position, chunk_geometry) in world_geometry {
|
||||
let buffers = GeometryBuffers::from_geometry(
|
||||
render_context,
|
||||
&chunk_geometry,
|
||||
BufferUsage::empty(),
|
||||
);
|
||||
self.chunk_buffers.insert(chunk_position, buffers);
|
||||
}
|
||||
|
||||
let elapsed = instant.elapsed();
|
||||
println!("World update took {:?}", elapsed);
|
||||
}
|
||||
|
||||
pub fn load_npc_geometry(
|
||||
&mut self,
|
||||
render_context: &RenderContext,
|
||||
) {
|
||||
self.world.npc.vertex_buffer = Some(render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&self.world.npc.vertices),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
}));
|
||||
pub fn load_npc_geometry(&mut self, render_context: &RenderContext) {
|
||||
self.world.npc.vertex_buffer = Some(render_context.device.create_buffer_init(
|
||||
&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&self.world.npc.vertices),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
},
|
||||
));
|
||||
|
||||
self.world.npc.index_buffer = Some(render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&self.world.npc.indices),
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
}));
|
||||
self.world.npc.index_buffer = Some(render_context.device.create_buffer_init(
|
||||
&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&self.world.npc.indices),
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
pub fn update_chunk_geometry(
|
||||
|
@ -287,31 +260,14 @@ impl WorldState {
|
|||
) {
|
||||
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(
|
||||
let geometry = chunk.to_geometry(
|
||||
offset,
|
||||
World::highlighted_for_chunk(self.highlighted, chunk_position).as_ref(),
|
||||
);
|
||||
|
||||
self.chunk_buffers.insert(
|
||||
chunk_position,
|
||||
(
|
||||
render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&vertices),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
}),
|
||||
render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytemuck::cast_slice(&indices),
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
}),
|
||||
indices.len(),
|
||||
),
|
||||
);
|
||||
let buffers =
|
||||
GeometryBuffers::from_geometry(render_context, &geometry, BufferUsage::empty());
|
||||
self.chunk_buffers.insert(chunk_position, buffers);
|
||||
}
|
||||
|
||||
pub fn toggle_wireframe(&mut self, render_context: &RenderContext) {
|
||||
|
@ -331,8 +287,8 @@ impl WorldState {
|
|||
|
||||
let (camera, projection) = Self::create_camera(render_context);
|
||||
|
||||
let (uniforms, uniform_buffer, world_uniform_layout, uniform_bind_group) =
|
||||
Self::create_uniforms(&camera, &projection, render_context);
|
||||
let (view, view_buffer, view_bind_group_layout, view_bind_group) =
|
||||
Self::create_view(&camera, &projection, render_context);
|
||||
|
||||
let (time, time_buffer, time_layout, time_bind_group) = Self::create_time(render_context);
|
||||
|
||||
|
@ -352,7 +308,7 @@ impl WorldState {
|
|||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[
|
||||
&texture_manager.bind_group_layout,
|
||||
&world_uniform_layout,
|
||||
&view_bind_group_layout,
|
||||
&time_layout,
|
||||
],
|
||||
});
|
||||
|
@ -364,9 +320,9 @@ impl WorldState {
|
|||
|
||||
let mut world_state = Self {
|
||||
render_pipeline,
|
||||
uniforms,
|
||||
uniform_buffer,
|
||||
uniform_bind_group,
|
||||
view,
|
||||
view_buffer,
|
||||
view_bind_group,
|
||||
texture_manager,
|
||||
camera,
|
||||
projection,
|
||||
|
@ -430,23 +386,22 @@ impl WorldState {
|
|||
|
||||
let tm = &self.texture_manager;
|
||||
render_pass.set_bind_group(0, tm.bind_group.as_ref().unwrap(), &[]);
|
||||
render_pass.set_bind_group(1, &self.uniform_bind_group, &[]);
|
||||
render_pass.set_bind_group(1, &self.view_bind_group, &[]);
|
||||
render_pass.set_bind_group(2, &self.time_bind_group, &[]);
|
||||
|
||||
let camera_pos = self.camera.position.to_vec();
|
||||
let camera_pos = Vector2::new(camera_pos.x, camera_pos.z);
|
||||
|
||||
for (position, (chunk_vertices, chunk_indices, index_count)) in &self.chunk_buffers {
|
||||
for (position, buffers) in &self.chunk_buffers {
|
||||
let pos = (position * CHUNK_SIZE).cast().unwrap();
|
||||
let pos = Vector2::new(pos.x, pos.z);
|
||||
if (pos - camera_pos).magnitude() > 300.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
render_pass.set_vertex_buffer(0, chunk_vertices.slice(..));
|
||||
render_pass.set_index_buffer(chunk_indices.slice(..), wgpu::IndexFormat::Uint16);
|
||||
render_pass.draw_indexed(0..*index_count as u32, 0, 0..1);
|
||||
triangle_count += index_count / 3;
|
||||
buffers.set_buffers(&mut render_pass);
|
||||
buffers.draw_indexed(&mut render_pass);
|
||||
triangle_count += buffers.index_count / 3;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -454,8 +409,9 @@ impl WorldState {
|
|||
let index_buffer = self.world.npc.index_buffer.as_ref();
|
||||
|
||||
render_pass.set_vertex_buffer(0, vertex_buffer.unwrap().slice(..));
|
||||
render_pass.set_index_buffer(index_buffer.unwrap().slice(..), wgpu::IndexFormat::Uint32);
|
||||
render_pass.draw_indexed(0..self.world.npc.indices.len() as u32 , 0, 0..1);
|
||||
render_pass
|
||||
.set_index_buffer(index_buffer.unwrap().slice(..), wgpu::IndexFormat::Uint32);
|
||||
render_pass.draw_indexed(0..self.world.npc.indices.len() as u32, 0, 0..1);
|
||||
}
|
||||
|
||||
triangle_count
|
||||
|
@ -504,12 +460,14 @@ impl WorldState {
|
|||
let camera = &self.camera;
|
||||
|
||||
let world = &mut self.world;
|
||||
if let Some((pos, axis)) = world.raycast(camera.position.to_vec(), camera.direction()) {
|
||||
if let Some((pos, face_normal)) =
|
||||
world.raycast(camera.position.to_vec(), camera.direction())
|
||||
{
|
||||
if button == &MouseButton::Left {
|
||||
world.set_block(pos.x as isize, pos.y as isize, pos.z as isize, None);
|
||||
self.update_chunk_geometry(render_context, pos / CHUNK_SIZE);
|
||||
} else if button == &MouseButton::Right {
|
||||
let new_pos = pos.cast().unwrap() - axis;
|
||||
let new_pos = pos.cast().unwrap() + face_normal;
|
||||
|
||||
world.set_block(
|
||||
new_pos.x as isize,
|
||||
|
@ -525,8 +483,8 @@ impl WorldState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn input_keyboard(&mut self, key_code: &VirtualKeyCode, state: &ElementState) {
|
||||
let pressed = state == &ElementState::Pressed;
|
||||
pub fn input_keyboard(&mut self, key_code: VirtualKeyCode, state: ElementState) {
|
||||
let pressed = state == ElementState::Pressed;
|
||||
match key_code {
|
||||
VirtualKeyCode::W => self.forward_pressed = pressed,
|
||||
VirtualKeyCode::S => self.backward_pressed = pressed,
|
||||
|
@ -545,13 +503,9 @@ impl WorldState {
|
|||
}
|
||||
}
|
||||
VirtualKeyCode::LShift if self.creative => {
|
||||
self.up_speed = if pressed {
|
||||
-1.0
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
self.up_speed = if pressed { -1.0 } else { 0.0 }
|
||||
}
|
||||
VirtualKeyCode::LControl => self.sprinting = state == &ElementState::Pressed,
|
||||
VirtualKeyCode::LControl => self.sprinting = state == ElementState::Pressed,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -609,13 +563,11 @@ impl WorldState {
|
|||
self.update_position(dt);
|
||||
self.update_aim(render_context);
|
||||
|
||||
self.uniforms
|
||||
self.view
|
||||
.update_view_projection(&self.camera, &self.projection);
|
||||
render_context.queue.write_buffer(
|
||||
&self.uniform_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&[self.uniforms]),
|
||||
);
|
||||
render_context
|
||||
.queue
|
||||
.write_buffer(&self.view_buffer, 0, bytemuck::cast_slice(&[self.view]));
|
||||
|
||||
self.time.time += dt.as_secs_f32();
|
||||
render_context.queue.write_buffer(
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
||||
|
||||
use crate::{render_context::RenderContext, texture::Texture, vertex::Vertex};
|
||||
use crate::{
|
||||
geometry::{Geometry, GeometryBuffers},
|
||||
render_context::RenderContext,
|
||||
texture::Texture,
|
||||
vertex::HudVertex,
|
||||
};
|
||||
|
||||
pub const DX: f32 = 20.0 / 640.0;
|
||||
pub const DY: f32 = 20.0 / 360.0;
|
||||
|
@ -100,16 +103,16 @@ impl TextRenderer {
|
|||
y: f32,
|
||||
c: u8,
|
||||
index_offset: u16,
|
||||
) -> ([Vertex; 4], [u16; 6]) {
|
||||
) -> ([HudVertex; 4], [u16; 6]) {
|
||||
let (tx, ty) = Self::char_uv(c);
|
||||
let s = 1.0 / 16.0;
|
||||
|
||||
#[rustfmt::skip]
|
||||
let vertices = [
|
||||
Vertex { position: [x, y, 0.0], texture_coordinates: [tx, ty, 0.0], ..Default::default() },
|
||||
Vertex { position: [x + DX, y, 0.0], texture_coordinates: [tx + s, ty, 0.0], ..Default::default() },
|
||||
Vertex { position: [x + DX, y - DY, 0.0], texture_coordinates: [tx + s, ty + s, 0.0], ..Default::default() },
|
||||
Vertex { position: [x, y - DY, 0.0], texture_coordinates: [tx, ty + s, 0.0], ..Default::default() },
|
||||
HudVertex { position: [x, y ], texture_coordinates: [tx, ty ] },
|
||||
HudVertex { position: [x + DX, y ], texture_coordinates: [tx + s, ty ] },
|
||||
HudVertex { position: [x + DX, y - DY], texture_coordinates: [tx + s, ty + s] },
|
||||
HudVertex { position: [x, y - DY], texture_coordinates: [tx, ty + s] },
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -121,7 +124,7 @@ impl TextRenderer {
|
|||
(vertices, indices)
|
||||
}
|
||||
|
||||
pub fn string_geometry(&self, mut x: f32, mut y: f32, string: &str) -> (Vec<Vertex>, Vec<u16>) {
|
||||
pub fn string_geometry(&self, mut x: f32, mut y: f32, string: &str) -> Geometry<HudVertex> {
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
|
||||
|
@ -141,7 +144,7 @@ impl TextRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
(vertices, indices)
|
||||
Geometry::new(vertices, indices)
|
||||
}
|
||||
|
||||
pub fn string_to_buffers(
|
||||
|
@ -150,25 +153,8 @@ impl TextRenderer {
|
|||
x: f32,
|
||||
y: f32,
|
||||
string: &str,
|
||||
) -> (wgpu::Buffer, wgpu::Buffer, usize) {
|
||||
let (vertices, indices) = self.string_geometry(x, y, string);
|
||||
|
||||
let vertex_buffer = render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("font renderer"),
|
||||
contents: bytemuck::cast_slice(&vertices),
|
||||
usage: wgpu::BufferUsage::VERTEX,
|
||||
});
|
||||
|
||||
let index_buffer = render_context
|
||||
.device
|
||||
.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("font renderer"),
|
||||
contents: bytemuck::cast_slice(&indices),
|
||||
usage: wgpu::BufferUsage::INDEX,
|
||||
});
|
||||
|
||||
(vertex_buffer, index_buffer, indices.len())
|
||||
) -> GeometryBuffers {
|
||||
let geometry = self.string_geometry(x, y, string);
|
||||
GeometryBuffers::from_geometry(render_context, &geometry, wgpu::BufferUsage::empty())
|
||||
}
|
||||
}
|
||||
|
|
104
src/vertex.rs
104
src/vertex.rs
|
@ -1,41 +1,89 @@
|
|||
use std::mem::size_of;
|
||||
|
||||
use wgpu::VertexAttribute;
|
||||
|
||||
pub trait Vertex {
|
||||
fn descriptor() -> wgpu::VertexBufferLayout<'static>;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Vertex {
|
||||
pub struct PlainVertex {
|
||||
pub position: [f32; 3],
|
||||
pub texture_coordinates: [f32; 3],
|
||||
pub texture_coordinates: [f32; 2],
|
||||
pub normal: [f32; 3],
|
||||
pub highlighted: i32,
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||
const PLAIN_VERTEX_ATTRIBUTES: &[VertexAttribute] = &wgpu::vertex_attr_array![
|
||||
0 => Float32x3,
|
||||
1 => Float32x2,
|
||||
2 => Float32x3,
|
||||
];
|
||||
|
||||
impl Vertex for PlainVertex {
|
||||
fn descriptor() -> wgpu::VertexBufferLayout<'static> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: size_of::<Vertex>() as wgpu::BufferAddress,
|
||||
array_stride: size_of::<Self>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
attributes: &[
|
||||
wgpu::VertexAttribute {
|
||||
offset: 0,
|
||||
shader_location: 0,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: 12,
|
||||
shader_location: 1,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: 24,
|
||||
shader_location: 2,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: 36,
|
||||
shader_location: 3,
|
||||
format: wgpu::VertexFormat::Sint32,
|
||||
},
|
||||
],
|
||||
attributes: PLAIN_VERTEX_ATTRIBUTES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Vertex used to represent HUD vertices.
|
||||
///
|
||||
/// A vertex with a 2D position and no normal, for representing UI elements.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct HudVertex {
|
||||
pub position: [f32; 2],
|
||||
pub texture_coordinates: [f32; 2],
|
||||
}
|
||||
|
||||
const HUD_VERTEX_ATTRIBUTES: &[VertexAttribute] = &wgpu::vertex_attr_array![
|
||||
0 => Float32x2,
|
||||
1 => Float32x2,
|
||||
];
|
||||
|
||||
impl Vertex for HudVertex {
|
||||
fn descriptor() -> wgpu::VertexBufferLayout<'static> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: size_of::<Self>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
attributes: HUD_VERTEX_ATTRIBUTES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Vertex used to represent block vertices.
|
||||
///
|
||||
/// Aside from the usual vertex position, texture coordinates and normal, this "vertex" also
|
||||
/// contains whether the block is highlighted (i.e. the player is pointing at the block) and its
|
||||
/// texture index (to address the texture arrays)
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct BlockVertex {
|
||||
pub position: [f32; 3],
|
||||
pub texture_coordinates: [f32; 2],
|
||||
pub normal: [f32; 3],
|
||||
pub highlighted: i32,
|
||||
pub texture_id: i32,
|
||||
}
|
||||
|
||||
const BLOCK_VERTEX_ATTRIBUTES: &[VertexAttribute] = &wgpu::vertex_attr_array![
|
||||
0 => Float32x3,
|
||||
1 => Float32x2,
|
||||
2 => Float32x3,
|
||||
3 => Sint32,
|
||||
4 => Sint32,
|
||||
];
|
||||
|
||||
impl Vertex for BlockVertex {
|
||||
fn descriptor() -> wgpu::VertexBufferLayout<'static> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: size_of::<Self>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
attributes: BLOCK_VERTEX_ATTRIBUTES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ use crate::camera::{Camera, Projection};
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Uniforms {
|
||||
pub struct View {
|
||||
view_position: [f32; 4],
|
||||
view_projection: [[f32; 4]; 4],
|
||||
}
|
||||
|
||||
impl Uniforms {
|
||||
impl View {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
view_position: [0.0; 4],
|
21
src/world.rs
21
src/world.rs
|
@ -1,14 +1,15 @@
|
|||
use crate::{
|
||||
chunk::{Block, Chunk, CHUNK_SIZE},
|
||||
vertex::Vertex,
|
||||
geometry::Geometry,
|
||||
npc::Npc,
|
||||
vertex::BlockVertex,
|
||||
};
|
||||
use cgmath::{InnerSpace, Vector3};
|
||||
use rayon::prelude::*;
|
||||
|
||||
pub struct World {
|
||||
pub chunks: Vec<Vec<Vec<Chunk>>>,
|
||||
pub npc: Npc
|
||||
pub npc: Npc,
|
||||
}
|
||||
|
||||
const WORLD_SIZE: Vector3<usize> = Vector3::new(
|
||||
|
@ -67,7 +68,7 @@ impl World {
|
|||
pub fn to_geometry(
|
||||
&self,
|
||||
highlighted: Option<(Vector3<usize>, Vector3<i32>)>,
|
||||
) -> Vec<(Vector3<usize>, Vec<Vertex>, Vec<u16>)> {
|
||||
) -> Vec<(Vector3<usize>, Geometry<BlockVertex>)> {
|
||||
let instant = std::time::Instant::now();
|
||||
|
||||
let chunks = &self.chunks;
|
||||
|
@ -75,17 +76,17 @@ impl World {
|
|||
.par_iter()
|
||||
.enumerate()
|
||||
.flat_map(|(y, chunks_y)| {
|
||||
let mut geometry = Vec::new();
|
||||
let mut chunk_geometry = Vec::new();
|
||||
for (z, chunks_z) in chunks_y.iter().enumerate() {
|
||||
for (x, chunk) in chunks_z.iter().enumerate() {
|
||||
let chunk_position = Vector3::new(x as usize, y as usize, z as usize);
|
||||
let offset = (chunk_position * CHUNK_SIZE).cast().unwrap();
|
||||
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));
|
||||
let geometry = chunk.to_geometry(offset, h.as_ref());
|
||||
chunk_geometry.push((Vector3::new(x, y, z), geometry));
|
||||
}
|
||||
}
|
||||
geometry
|
||||
chunk_geometry
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -182,15 +183,15 @@ impl World {
|
|||
if lengths.x < lengths.y && lengths.x < lengths.z {
|
||||
lengths.x += scale.x;
|
||||
position.x += step.x;
|
||||
face = Vector3::unit_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;
|
||||
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;
|
||||
face = Vector3::unit_z() * -step.z;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue