Move hud_state stuff into own "renderables"
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:
parent
11348f8086
commit
aa8d7aed83
10 changed files with 571 additions and 485 deletions
90
src/hud/debug_hud.rs
Normal file
90
src/hud/debug_hud.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
use cgmath::Point3;
|
||||
use wgpu::RenderPass;
|
||||
|
||||
use crate::{
|
||||
geometry::GeometryBuffers,
|
||||
render_context::RenderContext,
|
||||
text_renderer::{self, TextRenderer},
|
||||
};
|
||||
|
||||
pub struct DebugHud {
|
||||
text_renderer: TextRenderer,
|
||||
|
||||
fps_instant: Instant,
|
||||
fps_elapsed: Duration,
|
||||
fps_frames: u32,
|
||||
fps_geometry_buffers: GeometryBuffers<u16>,
|
||||
|
||||
coordinates_last: Point3<f32>,
|
||||
coordinates_geometry_buffers: GeometryBuffers<u16>,
|
||||
}
|
||||
|
||||
impl DebugHud {
|
||||
pub fn new(render_context: &RenderContext) -> Self {
|
||||
let text_renderer = TextRenderer::new(render_context).unwrap();
|
||||
let fps_geometry_buffers =
|
||||
text_renderer.string_to_buffers(&render_context, -0.98, 0.97, "");
|
||||
let coordinates_geometry_buffers =
|
||||
text_renderer.string_to_buffers(&render_context, -0.98, 0.97 - text_renderer::DY, "");
|
||||
|
||||
Self {
|
||||
text_renderer,
|
||||
|
||||
fps_instant: Instant::now(),
|
||||
fps_elapsed: Duration::default(),
|
||||
fps_frames: 0,
|
||||
fps_geometry_buffers,
|
||||
|
||||
coordinates_last: Point3::new(0.0, 0.0, 0.0),
|
||||
coordinates_geometry_buffers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, render_context: &RenderContext, position: &Point3<f32>) {
|
||||
let elapsed = self.fps_instant.elapsed();
|
||||
self.fps_instant = Instant::now();
|
||||
self.fps_elapsed += elapsed;
|
||||
self.fps_frames += 1;
|
||||
|
||||
if self.fps_elapsed.as_millis() >= 500 {
|
||||
let frametime = self.fps_elapsed / self.fps_frames;
|
||||
let fps = 1.0 / frametime.as_secs_f32();
|
||||
|
||||
let string = format!("{:<5.0} fps", fps);
|
||||
self.fps_geometry_buffers =
|
||||
self.text_renderer
|
||||
.string_to_buffers(render_context, -0.98, 0.97, &string);
|
||||
|
||||
self.fps_elapsed = Duration::from_secs(0);
|
||||
self.fps_frames = 0;
|
||||
}
|
||||
|
||||
if position != &self.coordinates_last {
|
||||
let string = format!("({:.1},{:.1},{:.1})", position.x, position.y, position.z,);
|
||||
self.coordinates_geometry_buffers = self.text_renderer.string_to_buffers(
|
||||
render_context,
|
||||
-0.98,
|
||||
0.97 - text_renderer::DY * 1.3,
|
||||
&string,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>) -> usize {
|
||||
let mut triangle_count = 0;
|
||||
|
||||
// Render the FPS text
|
||||
self.fps_geometry_buffers.apply_buffers(render_pass);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
triangle_count += self.fps_geometry_buffers.draw_indexed(render_pass);
|
||||
|
||||
// Render the coordinates text
|
||||
self.coordinates_geometry_buffers.apply_buffers(render_pass);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
triangle_count += self.coordinates_geometry_buffers.draw_indexed(render_pass);
|
||||
|
||||
triangle_count
|
||||
}
|
||||
}
|
97
src/hud/hotbar_hud.rs
Normal file
97
src/hud/hotbar_hud.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use wgpu::{BufferUsage, RenderPass};
|
||||
|
||||
use crate::{
|
||||
geometry::{Geometry, GeometryBuffers},
|
||||
hud::{UI_SCALE_X, UI_SCALE_Y},
|
||||
render_context::RenderContext,
|
||||
vertex::HudVertex,
|
||||
world::block::BlockType,
|
||||
};
|
||||
|
||||
pub struct HotbarHud {
|
||||
pub blocks: [Option<BlockType>; 9],
|
||||
pub last_blocks: [Option<BlockType>; 9],
|
||||
|
||||
pub geometry_buffers: GeometryBuffers<u16>,
|
||||
}
|
||||
|
||||
impl HotbarHud {
|
||||
pub fn new(render_context: &RenderContext) -> Self {
|
||||
let hotbar_blocks = [
|
||||
Some(BlockType::Dirt),
|
||||
Some(BlockType::Stone),
|
||||
Some(BlockType::Sand),
|
||||
None,
|
||||
Some(BlockType::Grass),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
];
|
||||
|
||||
Self {
|
||||
blocks: hotbar_blocks,
|
||||
last_blocks: [None; 9],
|
||||
|
||||
geometry_buffers: GeometryBuffers::from_geometry(
|
||||
render_context,
|
||||
&Geometry::<HudVertex, _>::default(),
|
||||
BufferUsage::empty(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, render_context: &RenderContext) {
|
||||
if self.blocks != self.last_blocks {
|
||||
self.geometry_buffers = GeometryBuffers::from_geometry(
|
||||
render_context,
|
||||
&self.block_vertices(),
|
||||
wgpu::BufferUsage::empty(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&'a self,
|
||||
render_context: &'a RenderContext,
|
||||
render_pass: &mut RenderPass<'a>,
|
||||
) -> usize {
|
||||
let texture_manager = render_context.texture_manager.as_ref().unwrap();
|
||||
|
||||
render_pass.set_bind_group(0, texture_manager.bind_group.as_ref().unwrap(), &[]);
|
||||
self.geometry_buffers.apply_buffers(render_pass);
|
||||
self.geometry_buffers.draw_indexed(render_pass)
|
||||
}
|
||||
|
||||
fn block_vertices(&self) -> Geometry<HudVertex, u16> {
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
|
||||
let mut index = 0;
|
||||
for cursor_index in 0..9 {
|
||||
if let Some(block) = self.blocks[cursor_index as usize] {
|
||||
let x = (-92 + 20 * cursor_index as i32) as f32;
|
||||
let texture_index = block.texture_indices().2.try_into().unwrap();
|
||||
|
||||
#[rustfmt::skip]
|
||||
vertices.extend(&[
|
||||
HudVertex { position: [UI_SCALE_X * (x + 5.0), -1.0 + UI_SCALE_Y * 18.0], texture_coordinates: [0.0, 0.0], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 19.0), -1.0 + UI_SCALE_Y * 18.0], texture_coordinates: [1.0, 0.0], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 19.0), -1.0 + UI_SCALE_Y * 4.0], texture_coordinates: [1.0, 1.0], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 5.0), -1.0 + UI_SCALE_Y * 4.0], texture_coordinates: [0.0, 1.0], texture_index },
|
||||
]);
|
||||
|
||||
#[rustfmt::skip]
|
||||
indices.extend(&[
|
||||
index, 2 + index, 1 + index,
|
||||
index, 3 + index, 2 + index,
|
||||
]);
|
||||
index += 4;
|
||||
}
|
||||
}
|
||||
|
||||
Geometry::new(vertices, indices)
|
||||
}
|
||||
}
|
141
src/hud/mod.rs
Normal file
141
src/hud/mod.rs
Normal file
|
@ -0,0 +1,141 @@
|
|||
use wgpu::{CommandEncoder, RenderPipeline, SwapChainTexture};
|
||||
|
||||
use crate::{
|
||||
render_context::RenderContext,
|
||||
state::PRIMITIVE_STATE,
|
||||
vertex::{HudVertex, Vertex},
|
||||
};
|
||||
|
||||
use self::{debug_hud::DebugHud, hotbar_hud::HotbarHud, widgets_hud::WidgetsHud};
|
||||
|
||||
pub mod debug_hud;
|
||||
pub mod hotbar_hud;
|
||||
pub mod widgets_hud;
|
||||
|
||||
// TODO update aspect ratio when resizing
|
||||
pub const UI_SCALE_X: f32 = 0.0045;
|
||||
pub const UI_SCALE_Y: f32 = 0.008;
|
||||
|
||||
pub struct Hud {
|
||||
pub widgets_hud: WidgetsHud,
|
||||
pub debug_hud: DebugHud,
|
||||
pub hotbar_hud: HotbarHud,
|
||||
|
||||
pub pipeline: RenderPipeline,
|
||||
}
|
||||
|
||||
impl Hud {
|
||||
pub fn new(render_context: &RenderContext) -> Self {
|
||||
Self {
|
||||
widgets_hud: WidgetsHud::new(render_context),
|
||||
debug_hud: DebugHud::new(render_context),
|
||||
hotbar_hud: HotbarHud::new(render_context),
|
||||
|
||||
pipeline: Self::create_render_pipeline(render_context),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_render_pipeline(render_context: &RenderContext) -> wgpu::RenderPipeline {
|
||||
let bind_group_layout =
|
||||
render_context
|
||||
.device
|
||||
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("GUI texture bind group layout"),
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
comparison: false,
|
||||
filtering: true,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2Array,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let module = &render_context
|
||||
.device
|
||||
.create_shader_module(&wgpu::ShaderModuleDescriptor {
|
||||
label: Some("UI shader"),
|
||||
flags: wgpu::ShaderFlags::all(),
|
||||
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/ui.wgsl").into()),
|
||||
});
|
||||
|
||||
let pipeline_layout =
|
||||
render_context
|
||||
.device
|
||||
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("UI render pipeline layout"),
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
render_context
|
||||
.device
|
||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("UI render pipeline"),
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module,
|
||||
entry_point: "main",
|
||||
buffers: &[HudVertex::descriptor()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module,
|
||||
entry_point: "main",
|
||||
targets: &[wgpu::ColorTargetState {
|
||||
format: render_context.swap_chain_descriptor.format,
|
||||
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
}),
|
||||
primitive: PRIMITIVE_STATE,
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
render_context: &crate::render_context::RenderContext,
|
||||
camera: &crate::camera::Camera,
|
||||
) {
|
||||
self.debug_hud.update(render_context, &camera.position);
|
||||
self.hotbar_hud.update(render_context);
|
||||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&'a self,
|
||||
render_context: &RenderContext,
|
||||
encoder: &mut CommandEncoder,
|
||||
frame: &SwapChainTexture,
|
||||
) -> usize {
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||
view: &frame.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
render_pass.set_pipeline(&self.pipeline);
|
||||
|
||||
self.widgets_hud.render(&mut render_pass)
|
||||
+ self.debug_hud.render(&mut render_pass)
|
||||
+ self.hotbar_hud.render(render_context, &mut render_pass)
|
||||
}
|
||||
}
|
175
src/hud/widgets_hud.rs
Normal file
175
src/hud/widgets_hud.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
// TODO Might want to move the hotbar outside
|
||||
use wgpu::{BindGroup, BufferUsage, RenderPass};
|
||||
|
||||
use crate::{
|
||||
geometry::{Geometry, GeometryBuffers},
|
||||
hud::{UI_SCALE_X, UI_SCALE_Y},
|
||||
render_context::RenderContext,
|
||||
texture::Texture,
|
||||
vertex::{HudVertex, Vertex},
|
||||
};
|
||||
|
||||
pub struct WidgetsHud {
|
||||
texture_bind_group: BindGroup,
|
||||
geometry_buffers: GeometryBuffers<u16>,
|
||||
hotbar_cursor_position: usize,
|
||||
}
|
||||
|
||||
impl WidgetsHud {
|
||||
pub fn new(render_context: &RenderContext) -> Self {
|
||||
let (_, texture_bind_group) = Self::create_textures(render_context);
|
||||
|
||||
let geometry = Geometry {
|
||||
vertices: VERTICES.to_vec(),
|
||||
indices: INDICES.to_vec(),
|
||||
};
|
||||
let geometry_buffers =
|
||||
GeometryBuffers::from_geometry(render_context, &geometry, BufferUsage::COPY_DST);
|
||||
|
||||
Self {
|
||||
texture_bind_group,
|
||||
geometry_buffers,
|
||||
hotbar_cursor_position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_textures(render_context: &RenderContext) -> (wgpu::BindGroupLayout, wgpu::BindGroup) {
|
||||
let texture = Texture::from_bytes(
|
||||
render_context,
|
||||
include_bytes!("../../assets/gui/widgets.png"),
|
||||
"Texture GUI widgets",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let sampler = render_context
|
||||
.device
|
||||
.create_sampler(&wgpu::SamplerDescriptor {
|
||||
mag_filter: wgpu::FilterMode::Nearest,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
..wgpu::SamplerDescriptor::default()
|
||||
});
|
||||
|
||||
let bind_group_layout =
|
||||
render_context
|
||||
.device
|
||||
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("GUI texture bind group layout"),
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
comparison: false,
|
||||
filtering: true,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2Array,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let bind_group = render_context
|
||||
.device
|
||||
.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: Some("GUI texture bind group"),
|
||||
layout: &bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::TextureView(&texture.view),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
(bind_group_layout, bind_group)
|
||||
}
|
||||
|
||||
pub fn set_hotbar_cursor(&mut self, render_context: &RenderContext, i: usize) {
|
||||
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 as i32 + delta).rem_euclid(9) as usize;
|
||||
self.redraw_hotbar_cursor(render_context);
|
||||
}
|
||||
|
||||
pub fn redraw_hotbar_cursor(&self, render_context: &RenderContext) {
|
||||
let x = (-92 + 20 * self.hotbar_cursor_position as i32) as f32;
|
||||
let texture_index = 0;
|
||||
|
||||
#[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], texture_index },
|
||||
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], texture_index },
|
||||
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], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x ), -1.0 + UI_SCALE_Y * -1.0], texture_coordinates: [ 0.0 / 256.0, 46.0 / 256.0], texture_index },
|
||||
];
|
||||
|
||||
render_context.queue.write_buffer(
|
||||
&self.geometry_buffers.vertices,
|
||||
HudVertex::descriptor().array_stride * 8,
|
||||
bytemuck::cast_slice(&vertices),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>) -> usize {
|
||||
// Render the HUD elements
|
||||
self.geometry_buffers.apply_buffers(render_pass);
|
||||
render_pass.set_bind_group(0, &self.texture_bind_group, &[]);
|
||||
self.geometry_buffers.draw_indexed(render_pass);
|
||||
render_pass.draw_indexed(0..self.geometry_buffers.index_count as u32, 0, 0..1);
|
||||
|
||||
INDICES.len() / 3
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const VERTICES: [HudVertex; 12] = [
|
||||
// Crosshair
|
||||
HudVertex { position: [UI_SCALE_X * -8.0, UI_SCALE_Y * 8.0], texture_coordinates: [240.0 / 256.0, 0.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * 8.0, UI_SCALE_Y * 8.0], texture_coordinates: [ 1.0, 0.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * 8.0, UI_SCALE_Y * -8.0], texture_coordinates: [ 1.0, 16.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * -8.0, UI_SCALE_Y * -8.0], texture_coordinates: [240.0 / 256.0, 16.0 / 256.0], texture_index: 0 },
|
||||
|
||||
// Hotbar
|
||||
HudVertex { position: [UI_SCALE_X * -91.0, -1.0 + UI_SCALE_Y * 22.0], texture_coordinates: [ 0.0 / 256.0, 0.0 / 256.0], texture_index: 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], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * 91.0, -1.0 ], texture_coordinates: [182.0 / 256.0, 22.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * -91.0, -1.0 ], texture_coordinates: [ 0.0 / 256.0, 22.0 / 256.0], texture_index: 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], texture_index: 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], texture_index: 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], texture_index: 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], texture_index: 0 },
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const 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,
|
||||
];
|
|
@ -1,18 +1,18 @@
|
|||
mod aabb;
|
||||
mod camera;
|
||||
mod geometry;
|
||||
mod hud;
|
||||
mod npc;
|
||||
mod player;
|
||||
mod render_context;
|
||||
mod renderable;
|
||||
mod state;
|
||||
mod text_renderer;
|
||||
mod texture;
|
||||
mod time;
|
||||
mod utils;
|
||||
mod vertex;
|
||||
mod view;
|
||||
mod world;
|
||||
mod utils;
|
||||
mod player;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use wgpu::SwapChainError;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use wgpu::RenderPass;
|
||||
|
||||
use crate::{camera::Camera, render_context::RenderContext, view::View};
|
||||
|
||||
pub trait Renderable {
|
||||
fn update(
|
||||
&mut self,
|
||||
render_context: &RenderContext,
|
||||
dt: Duration,
|
||||
render_time: Duration,
|
||||
camera: &Camera,
|
||||
);
|
||||
fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize;
|
||||
}
|
|
@ -1,398 +0,0 @@
|
|||
use std::{
|
||||
convert::TryInto,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use cgmath::Vector3;
|
||||
use wgpu::{BufferUsage, CommandEncoder, SwapChainTexture};
|
||||
|
||||
use crate::{
|
||||
geometry::{Geometry, GeometryBuffers},
|
||||
render_context::RenderContext,
|
||||
state::PRIMITIVE_STATE,
|
||||
text_renderer::{self, TextRenderer},
|
||||
texture::Texture,
|
||||
vertex::{HudVertex, Vertex},
|
||||
world::block::BlockType,
|
||||
};
|
||||
|
||||
// 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,
|
||||
hud_geometry_buffers: GeometryBuffers<u16>,
|
||||
|
||||
text_renderer: TextRenderer,
|
||||
|
||||
fps_geometry_buffers: GeometryBuffers<u16>,
|
||||
fps_instant: Instant,
|
||||
fps_frames: u32,
|
||||
fps_elapsed: Duration,
|
||||
|
||||
coordinates_geometry_buffers: GeometryBuffers<u16>,
|
||||
coordinates_last: Vector3<f32>,
|
||||
|
||||
pub hotbar_cursor_position: usize,
|
||||
hotbar_blocks: [Option<BlockType>; 9],
|
||||
hotbar_block_buffers: Option<GeometryBuffers<u16>>,
|
||||
}
|
||||
|
||||
impl HudState {
|
||||
pub fn new(render_context: &RenderContext) -> Self {
|
||||
let (texture_bind_group_layout, texture_bind_group) = Self::create_textures(render_context);
|
||||
|
||||
let render_pipeline =
|
||||
Self::create_render_pipeline(render_context, &[&texture_bind_group_layout]);
|
||||
|
||||
// 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_geometry_buffers =
|
||||
text_renderer.string_to_buffers(&render_context, -0.98, 0.97, "");
|
||||
let coordinates_geometry_buffers =
|
||||
text_renderer.string_to_buffers(&render_context, -0.98, 0.97 - text_renderer::DY, "");
|
||||
|
||||
let hotbar_blocks = [
|
||||
Some(BlockType::Dirt),
|
||||
Some(BlockType::Stone),
|
||||
Some(BlockType::Sand),
|
||||
None,
|
||||
Some(BlockType::Grass),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
];
|
||||
|
||||
let mut hud_state = Self {
|
||||
texture_bind_group,
|
||||
render_pipeline,
|
||||
text_renderer,
|
||||
|
||||
hud_geometry_buffers,
|
||||
|
||||
fps_geometry_buffers,
|
||||
fps_instant: Instant::now(),
|
||||
fps_frames: 0,
|
||||
fps_elapsed: Duration::from_secs(0),
|
||||
|
||||
coordinates_geometry_buffers,
|
||||
coordinates_last: Vector3::new(0.0, 0.0, 0.0),
|
||||
|
||||
hotbar_cursor_position: 0,
|
||||
hotbar_blocks,
|
||||
hotbar_block_buffers: None,
|
||||
};
|
||||
|
||||
hud_state.hotbar_block_buffers = Some(GeometryBuffers::from_geometry(
|
||||
render_context,
|
||||
&hud_state.hotbar_block_vertices(),
|
||||
wgpu::BufferUsage::empty(),
|
||||
));
|
||||
|
||||
hud_state
|
||||
}
|
||||
|
||||
pub fn update(&mut self, render_context: &RenderContext, position: &Vector3<f32>) {
|
||||
let elapsed = self.fps_instant.elapsed();
|
||||
self.fps_instant = Instant::now();
|
||||
self.fps_elapsed += elapsed;
|
||||
self.fps_frames += 1;
|
||||
|
||||
if self.fps_elapsed.as_millis() >= 500 {
|
||||
let frametime = self.fps_elapsed / self.fps_frames;
|
||||
let fps = 1.0 / frametime.as_secs_f32();
|
||||
|
||||
let string = format!("{:<5.0} fps", fps);
|
||||
self.fps_geometry_buffers =
|
||||
self.text_renderer
|
||||
.string_to_buffers(render_context, -0.98, 0.97, &string);
|
||||
|
||||
self.fps_elapsed = Duration::from_secs(0);
|
||||
self.fps_frames = 0;
|
||||
}
|
||||
|
||||
if position != &self.coordinates_last {
|
||||
let string = format!("({:.1},{:.1},{:.1})", position.x, position.y, position.z,);
|
||||
self.coordinates_geometry_buffers = self.text_renderer.string_to_buffers(
|
||||
render_context,
|
||||
-0.98,
|
||||
0.97 - text_renderer::DY * 1.3,
|
||||
&string,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&self,
|
||||
render_context: &RenderContext,
|
||||
frame: &SwapChainTexture,
|
||||
render_encoder: &mut CommandEncoder,
|
||||
) -> anyhow::Result<usize> {
|
||||
let mut render_pass = render_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||
view: &frame.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&self.render_pipeline);
|
||||
|
||||
// Render the HUD elements
|
||||
self.hud_geometry_buffers.apply_buffers(&mut render_pass);
|
||||
render_pass.set_bind_group(0, &self.texture_bind_group, &[]);
|
||||
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 the FPS text
|
||||
self.fps_geometry_buffers.apply_buffers(&mut render_pass);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
self.fps_geometry_buffers.draw_indexed(&mut render_pass);
|
||||
|
||||
// Render the coordinates text
|
||||
self.coordinates_geometry_buffers
|
||||
.apply_buffers(&mut render_pass);
|
||||
render_pass.set_bind_group(0, &self.text_renderer.bind_group, &[]);
|
||||
self.coordinates_geometry_buffers
|
||||
.draw_indexed(&mut render_pass);
|
||||
|
||||
// Render the blocks on the hot bar
|
||||
let texture_manager = render_context.texture_manager.as_ref().unwrap();
|
||||
render_pass.set_bind_group(0, texture_manager.bind_group.as_ref().unwrap(), &[]);
|
||||
self.hotbar_block_buffers
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.apply_buffers(&mut render_pass);
|
||||
self.hotbar_block_buffers
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.draw_indexed(&mut render_pass);
|
||||
|
||||
Ok(HUD_INDICES.len() / 3)
|
||||
}
|
||||
|
||||
pub fn selected_block_type(&self) -> Option<BlockType> {
|
||||
self.hotbar_blocks[self.hotbar_cursor_position]
|
||||
}
|
||||
|
||||
fn hotbar_block_vertices(&self) -> Geometry<HudVertex, u16> {
|
||||
let mut vertices = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
|
||||
let mut index = 0;
|
||||
for cursor_index in 0..9 {
|
||||
if let Some(block) = self.hotbar_blocks[cursor_index as usize] {
|
||||
let x = (-92 + 20 * cursor_index as i32) as f32;
|
||||
let texture_index = block.texture_indices().2.try_into().unwrap();
|
||||
|
||||
#[rustfmt::skip]
|
||||
vertices.extend(&[
|
||||
HudVertex { position: [UI_SCALE_X * (x + 5.0), -1.0 + UI_SCALE_Y * 18.0], texture_coordinates: [0.0, 0.0], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 19.0), -1.0 + UI_SCALE_Y * 18.0], texture_coordinates: [1.0, 0.0], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 19.0), -1.0 + UI_SCALE_Y * 4.0], texture_coordinates: [1.0, 1.0], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x + 5.0), -1.0 + UI_SCALE_Y * 4.0], texture_coordinates: [0.0, 1.0], texture_index },
|
||||
]);
|
||||
|
||||
#[rustfmt::skip]
|
||||
indices.extend(&[
|
||||
index, 2 + index, 1 + index,
|
||||
index, 3 + index, 2 + index,
|
||||
]);
|
||||
index += 4;
|
||||
}
|
||||
}
|
||||
|
||||
Geometry::new(vertices, indices)
|
||||
}
|
||||
|
||||
pub fn redraw_hotbar_cursor(&self, render_context: &RenderContext) {
|
||||
let x = (-92 + 20 * self.hotbar_cursor_position as i32) as f32;
|
||||
let texture_index = 0;
|
||||
|
||||
#[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], texture_index },
|
||||
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], texture_index },
|
||||
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], texture_index },
|
||||
HudVertex { position: [UI_SCALE_X * (x ), -1.0 + UI_SCALE_Y * -1.0], texture_coordinates: [ 0.0 / 256.0, 46.0 / 256.0], texture_index },
|
||||
];
|
||||
|
||||
render_context.queue.write_buffer(
|
||||
&self.hud_geometry_buffers.vertices,
|
||||
HudVertex::descriptor().array_stride * 8,
|
||||
bytemuck::cast_slice(&vertices),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn set_hotbar_cursor(&mut self, render_context: &RenderContext, i: usize) {
|
||||
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 as i32 + delta).rem_euclid(9) as usize;
|
||||
self.redraw_hotbar_cursor(render_context);
|
||||
}
|
||||
|
||||
fn create_textures(render_context: &RenderContext) -> (wgpu::BindGroupLayout, wgpu::BindGroup) {
|
||||
let texture = Texture::from_bytes(
|
||||
render_context,
|
||||
include_bytes!("../../assets/gui/widgets.png"),
|
||||
"Texture GUI widgets",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let sampler = render_context
|
||||
.device
|
||||
.create_sampler(&wgpu::SamplerDescriptor {
|
||||
mag_filter: wgpu::FilterMode::Nearest,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
..wgpu::SamplerDescriptor::default()
|
||||
});
|
||||
|
||||
let bind_group_layout =
|
||||
render_context
|
||||
.device
|
||||
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("GUI texture bind group layout"),
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
comparison: false,
|
||||
filtering: true,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2Array,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let bind_group = render_context
|
||||
.device
|
||||
.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: Some("GUI texture bind group"),
|
||||
layout: &bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::TextureView(&texture.view),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
(bind_group_layout, bind_group)
|
||||
}
|
||||
|
||||
fn create_render_pipeline(
|
||||
render_context: &RenderContext,
|
||||
bind_group_layouts: &[&wgpu::BindGroupLayout],
|
||||
) -> wgpu::RenderPipeline {
|
||||
let module = &render_context
|
||||
.device
|
||||
.create_shader_module(&wgpu::ShaderModuleDescriptor {
|
||||
label: Some("UI shader"),
|
||||
flags: wgpu::ShaderFlags::all(),
|
||||
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/ui.wgsl").into()),
|
||||
});
|
||||
|
||||
let pipeline_layout =
|
||||
render_context
|
||||
.device
|
||||
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("UI render pipeline layout"),
|
||||
bind_group_layouts,
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
render_context
|
||||
.device
|
||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("UI render pipeline"),
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module,
|
||||
entry_point: "main",
|
||||
buffers: &[HudVertex::descriptor()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module,
|
||||
entry_point: "main",
|
||||
targets: &[wgpu::ColorTargetState {
|
||||
format: render_context.swap_chain_descriptor.format,
|
||||
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
}),
|
||||
primitive: PRIMITIVE_STATE,
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const HUD_VERTICES: [HudVertex; 12] = [
|
||||
// Crosshair
|
||||
HudVertex { position: [UI_SCALE_X * -8.0, UI_SCALE_Y * 8.0], texture_coordinates: [240.0 / 256.0, 0.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * 8.0, UI_SCALE_Y * 8.0], texture_coordinates: [ 1.0, 0.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * 8.0, UI_SCALE_Y * -8.0], texture_coordinates: [ 1.0, 16.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * -8.0, UI_SCALE_Y * -8.0], texture_coordinates: [240.0 / 256.0, 16.0 / 256.0], texture_index: 0 },
|
||||
|
||||
// Hotbar
|
||||
HudVertex { position: [UI_SCALE_X * -91.0, -1.0 + UI_SCALE_Y * 22.0], texture_coordinates: [ 0.0 / 256.0, 0.0 / 256.0], texture_index: 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], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * 91.0, -1.0 ], texture_coordinates: [182.0 / 256.0, 22.0 / 256.0], texture_index: 0 },
|
||||
HudVertex { position: [UI_SCALE_X * -91.0, -1.0 ], texture_coordinates: [ 0.0 / 256.0, 22.0 / 256.0], texture_index: 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], texture_index: 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], texture_index: 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], texture_index: 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], texture_index: 0 },
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
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,
|
||||
];
|
|
@ -1,19 +1,16 @@
|
|||
pub mod hud_state;
|
||||
pub mod world_state;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use cgmath::EuclideanSpace;
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
event::{DeviceEvent, ElementState, MouseScrollDelta, VirtualKeyCode, WindowEvent},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
use hud_state::HudState;
|
||||
use world_state::WorldState;
|
||||
|
||||
use crate::{render_context::RenderContext, texture::TextureManager};
|
||||
use crate::{hud::Hud, render_context::RenderContext, texture::TextureManager};
|
||||
|
||||
pub const PRIMITIVE_STATE: wgpu::PrimitiveState = wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
|
@ -29,9 +26,10 @@ pub struct State {
|
|||
pub window_size: PhysicalSize<u32>,
|
||||
render_context: RenderContext,
|
||||
pub world_state: WorldState,
|
||||
hud_state: HudState,
|
||||
|
||||
pub mouse_grabbed: bool,
|
||||
|
||||
pub hud: Hud,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -110,16 +108,18 @@ impl State {
|
|||
render_context.texture_manager = Some(texture_manager);
|
||||
|
||||
let world_state = WorldState::new(&render_context);
|
||||
let hud_state = HudState::new(&render_context);
|
||||
|
||||
let hud = Hud::new(&render_context);
|
||||
|
||||
Self {
|
||||
window_size,
|
||||
render_context,
|
||||
|
||||
world_state,
|
||||
hud_state,
|
||||
|
||||
mouse_grabbed: false,
|
||||
|
||||
hud,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,18 +137,24 @@ impl State {
|
|||
);
|
||||
}
|
||||
|
||||
fn set_hotbar_cursor(&mut self, i: usize) {
|
||||
self.hud
|
||||
.widgets_hud
|
||||
.set_hotbar_cursor(&self.render_context, i);
|
||||
}
|
||||
|
||||
fn input_keyboard(&mut self, key_code: VirtualKeyCode, state: ElementState) {
|
||||
if state == ElementState::Pressed {
|
||||
match key_code {
|
||||
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),
|
||||
VirtualKeyCode::Key1 => self.set_hotbar_cursor(0),
|
||||
VirtualKeyCode::Key2 => self.set_hotbar_cursor(1),
|
||||
VirtualKeyCode::Key3 => self.set_hotbar_cursor(2),
|
||||
VirtualKeyCode::Key4 => self.set_hotbar_cursor(3),
|
||||
VirtualKeyCode::Key5 => self.set_hotbar_cursor(4),
|
||||
VirtualKeyCode::Key6 => self.set_hotbar_cursor(5),
|
||||
VirtualKeyCode::Key7 => self.set_hotbar_cursor(6),
|
||||
VirtualKeyCode::Key8 => self.set_hotbar_cursor(7),
|
||||
VirtualKeyCode::Key9 => self.set_hotbar_cursor(8),
|
||||
_ => self.world_state.input_keyboard(key_code, state),
|
||||
}
|
||||
} else {
|
||||
|
@ -175,14 +181,15 @@ impl State {
|
|||
} if self.mouse_grabbed => self.world_state.input_mouse_button(
|
||||
button,
|
||||
&self.render_context,
|
||||
self.hud_state.selected_block_type(),
|
||||
None, // TODO
|
||||
),
|
||||
|
||||
WindowEvent::MouseWheel {
|
||||
delta: MouseScrollDelta::LineDelta(_, delta),
|
||||
..
|
||||
} => self
|
||||
.hud_state
|
||||
.hud
|
||||
.widgets_hud
|
||||
.move_hotbar_cursor(&self.render_context, -*delta as i32),
|
||||
|
||||
_ => (),
|
||||
|
@ -198,37 +205,35 @@ impl State {
|
|||
pub fn update(&mut self, dt: Duration, render_time: Duration) {
|
||||
self.world_state
|
||||
.update(dt, render_time, &self.render_context);
|
||||
self.hud_state.update(
|
||||
&self.render_context,
|
||||
&self.world_state.player.view.camera.position.to_vec(),
|
||||
);
|
||||
|
||||
self.hud
|
||||
.update(&self.render_context, &self.world_state.player.view.camera)
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> anyhow::Result<(usize, Duration)> {
|
||||
let render_start = Instant::now();
|
||||
|
||||
Ok({
|
||||
let frame = self.render_context.swap_chain.get_current_frame()?.output;
|
||||
let frame = self.render_context.swap_chain.get_current_frame()?.output;
|
||||
|
||||
let mut render_encoder = self
|
||||
.render_context
|
||||
.device
|
||||
.create_command_encoder(&Default::default());
|
||||
let mut render_encoder = self
|
||||
.render_context
|
||||
.device
|
||||
.create_command_encoder(&Default::default());
|
||||
|
||||
let mut triangle_count = 0;
|
||||
triangle_count +=
|
||||
self.world_state
|
||||
.render(&self.render_context, &frame, &mut render_encoder);
|
||||
triangle_count +=
|
||||
self.hud_state
|
||||
.render(&self.render_context, &frame, &mut render_encoder)?;
|
||||
let mut triangle_count = 0;
|
||||
triangle_count +=
|
||||
self.world_state
|
||||
.render(&self.render_context, &frame, &mut render_encoder);
|
||||
|
||||
self.render_context
|
||||
.queue
|
||||
.submit(std::iter::once(render_encoder.finish()));
|
||||
let render_time = render_start.elapsed();
|
||||
triangle_count += self
|
||||
.hud
|
||||
.render(&self.render_context, &mut render_encoder, &frame);
|
||||
|
||||
(triangle_count, render_time)
|
||||
})
|
||||
self.render_context
|
||||
.queue
|
||||
.submit(std::iter::once(render_encoder.finish()));
|
||||
let render_time = render_start.elapsed();
|
||||
|
||||
Ok((triangle_count, render_time))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use winit::{
|
|||
use crate::{
|
||||
player::Player,
|
||||
render_context::RenderContext,
|
||||
renderable::Renderable,
|
||||
texture::Texture,
|
||||
time::Time,
|
||||
vertex::{BlockVertex, Vertex},
|
||||
|
@ -123,8 +122,7 @@ impl WorldState {
|
|||
let (time, time_buffer, time_layout, time_bind_group) = Self::create_time(render_context);
|
||||
let player = Player::new(render_context);
|
||||
|
||||
let mut world = World::new();
|
||||
world.npc.load_geometry(render_context);
|
||||
let world = World::new(render_context);
|
||||
|
||||
let shader = render_context.device.create_shader_module(
|
||||
&(wgpu::ShaderModuleDescriptor {
|
||||
|
@ -196,7 +194,6 @@ impl WorldState {
|
|||
stencil_ops: None,
|
||||
}),
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&self.render_pipeline);
|
||||
|
||||
let texture_manager = render_context.texture_manager.as_ref().unwrap();
|
||||
|
@ -236,24 +233,18 @@ impl WorldState {
|
|||
VirtualKeyCode::D => self.player.right_pressed = pressed,
|
||||
VirtualKeyCode::F2 if pressed => self.player.creative ^= true,
|
||||
VirtualKeyCode::Space => {
|
||||
// TODO aaaaaaaaaaaaaaaaaa
|
||||
self.player.up_speed = if pressed {
|
||||
if self.player.creative {
|
||||
1.0
|
||||
} else {
|
||||
if self.player.up_speed.abs() < 0.05 {
|
||||
0.6
|
||||
} else {
|
||||
self.player.up_speed
|
||||
}
|
||||
self.player.up_speed = match (pressed, self.player.creative) {
|
||||
// Creative
|
||||
(true, true) => 1.0,
|
||||
(false, true) => 0.0,
|
||||
|
||||
// Not creative
|
||||
(true, false) => {
|
||||
// TODO Don't allow player to jump in mid-air
|
||||
0.6
|
||||
}
|
||||
} else {
|
||||
if self.player.creative {
|
||||
0.0
|
||||
} else {
|
||||
self.player.up_speed
|
||||
}
|
||||
}
|
||||
(false, false) => self.player.up_speed,
|
||||
};
|
||||
}
|
||||
VirtualKeyCode::LShift if self.player.creative => {
|
||||
self.player.up_speed = if pressed { -1.0 } else { 0.0 }
|
||||
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
|||
camera::Camera,
|
||||
npc::Npc,
|
||||
render_context::RenderContext,
|
||||
renderable::Renderable,
|
||||
view::View,
|
||||
world::{
|
||||
block::{Block, BlockType},
|
||||
|
@ -42,9 +41,9 @@ pub const WORLD_HEIGHT: isize = 16 * 16 / CHUNK_ISIZE;
|
|||
|
||||
const DEBUG_IO: bool = false;
|
||||
|
||||
impl Renderable for World {
|
||||
impl World {
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
fn update(
|
||||
pub fn update(
|
||||
&mut self,
|
||||
render_context: &RenderContext,
|
||||
dt: Duration,
|
||||
|
@ -148,10 +147,11 @@ impl Renderable for World {
|
|||
}
|
||||
}
|
||||
|
||||
fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize {
|
||||
pub fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize {
|
||||
let mut triangle_count = 0;
|
||||
|
||||
for (position, chunk) in &self.chunks {
|
||||
// TODO Reimplement frustrum culling
|
||||
if !chunk.is_visible(position * CHUNK_ISIZE, &view) {
|
||||
continue;
|
||||
}
|
||||
|
@ -171,9 +171,10 @@ impl Renderable for World {
|
|||
}
|
||||
|
||||
impl World {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(render_context: &RenderContext) -> Self {
|
||||
let chunks = AHashMap::new();
|
||||
let npc = Npc::load();
|
||||
let mut npc = Npc::load();
|
||||
npc.load_geometry(render_context);
|
||||
|
||||
let chunk_database = sled::Config::new()
|
||||
.path("chunks")
|
||||
|
|
Loading…
Reference in a new issue