mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added session, documented, improved structure
This commit is contained in:
parent
d559d633ab
commit
c9d877de7a
@ -25,3 +25,5 @@ vek = "0.9"
|
|||||||
glsl-include = "0.2"
|
glsl-include = "0.2"
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
lazy_static = "1.1"
|
lazy_static = "1.1"
|
||||||
|
log = "0.4"
|
||||||
|
pretty_env_logger = "0.3"
|
||||||
|
25
voxygen/shaders/character.frag
Normal file
25
voxygen/shaders/character.frag
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec3 f_pos;
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_locals {
|
||||||
|
mat4 model_mat;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_globals {
|
||||||
|
mat4 view_mat;
|
||||||
|
mat4 proj_mat;
|
||||||
|
vec4 cam_pos;
|
||||||
|
vec4 focus_pos;
|
||||||
|
vec4 view_distance;
|
||||||
|
vec4 tod;
|
||||||
|
vec4 time;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 tgt_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
tgt_color = vec4(f_pos, 1.0);
|
||||||
|
}
|
32
voxygen/shaders/character.vert
Normal file
32
voxygen/shaders/character.vert
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec3 v_pos;
|
||||||
|
in vec3 v_col;
|
||||||
|
in uint v_bone;
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_locals {
|
||||||
|
mat4 model_mat;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_globals {
|
||||||
|
mat4 view_mat;
|
||||||
|
mat4 proj_mat;
|
||||||
|
vec4 cam_pos;
|
||||||
|
vec4 focus_pos;
|
||||||
|
vec4 view_distance;
|
||||||
|
vec4 tod;
|
||||||
|
vec4 time;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec3 f_pos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
f_pos = v_pos;
|
||||||
|
|
||||||
|
gl_Position =
|
||||||
|
proj_mat *
|
||||||
|
view_mat *
|
||||||
|
vec4(0.5 * v_pos + cam_pos.xyz, 1);
|
||||||
|
}
|
@ -4,7 +4,7 @@ in vec3 f_pos;
|
|||||||
|
|
||||||
layout (std140)
|
layout (std140)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
mat4 model_mat;
|
vec4 nul;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (std140)
|
layout (std140)
|
||||||
@ -21,5 +21,5 @@ uniform u_globals {
|
|||||||
out vec4 tgt_color;
|
out vec4 tgt_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
tgt_color = vec4(1.0, 0.0, 0.0, 1.0);
|
tgt_color = vec4(f_pos, 1.0);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ in vec3 v_pos;
|
|||||||
|
|
||||||
layout (std140)
|
layout (std140)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
mat4 model_mat;
|
vec4 nul;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (std140)
|
layout (std140)
|
||||||
@ -26,5 +26,6 @@ void main() {
|
|||||||
gl_Position =
|
gl_Position =
|
||||||
proj_mat *
|
proj_mat *
|
||||||
view_mat *
|
view_mat *
|
||||||
vec4(3000 * v_pos + cam_pos.xyz, 1);
|
vec4(v_pos + cam_pos.xyz, 1);
|
||||||
|
gl_Position.z = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
// Library
|
|
||||||
use gfx::{
|
|
||||||
handle::Buffer,
|
|
||||||
traits::{FactoryExt, Pod},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Crate
|
|
||||||
use crate::render_ctx::{RenderCtx, Resources};
|
|
||||||
|
|
||||||
type ConstBuffer<T> = Buffer<Resources, T>;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ConstHandle<T: Copy + Pod> {
|
|
||||||
buffer: ConstBuffer<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Copy + Pod> ConstHandle<T> {
|
|
||||||
pub fn new(render_ctx: &mut RenderCtx) -> Self {
|
|
||||||
Self {
|
|
||||||
buffer: render_ctx
|
|
||||||
.factory_mut()
|
|
||||||
.create_constant_buffer(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&self, render_ctx: &mut RenderCtx, consts: T) {
|
|
||||||
render_ctx
|
|
||||||
.encoder_mut()
|
|
||||||
.update_buffer(&self.buffer, &[consts], 0)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn buffer(&self) -> &ConstBuffer<T> { &self.buffer }
|
|
||||||
}
|
|
22
voxygen/src/error.rs
Normal file
22
voxygen/src/error.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Standard
|
||||||
|
use std::any;
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::render::RenderError;
|
||||||
|
|
||||||
|
/// Represents any error that may be triggered by Voxygen
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// A miscellaneous error relating to a backend dependency
|
||||||
|
BackendError(Box<any::Any>),
|
||||||
|
/// An error relating the rendering subsystem
|
||||||
|
RenderError(RenderError),
|
||||||
|
// A miscellaneous error with an unknown or unspecified source
|
||||||
|
Other(failure::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RenderError> for Error {
|
||||||
|
fn from(err: RenderError) -> Self {
|
||||||
|
Error::RenderError(err)
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
// Library
|
|
||||||
use gfx::{
|
|
||||||
// Urgh
|
|
||||||
gfx_defines,
|
|
||||||
gfx_constant_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
|
||||||
};
|
|
||||||
|
|
||||||
gfx_defines! {
|
|
||||||
constant GlobalConsts {
|
|
||||||
view_mat: [[f32; 4]; 4] = "view_mat",
|
|
||||||
proj_mat: [[f32; 4]; 4] = "proj_mat",
|
|
||||||
cam_origin: [f32; 4] = "cam_origin",
|
|
||||||
play_origin: [f32; 4] = "play_origin",
|
|
||||||
view_distance: [f32; 4] = "view_distance",
|
|
||||||
time: [f32; 4] = "time",
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +1,28 @@
|
|||||||
mod menu;
|
pub mod error;
|
||||||
mod render;
|
pub mod menu;
|
||||||
mod window;
|
pub mod render;
|
||||||
|
pub mod scene;
|
||||||
|
pub mod session;
|
||||||
|
pub mod window;
|
||||||
|
|
||||||
|
// Reexports
|
||||||
|
pub use crate::error::Error;
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
use std::{
|
use std::mem;
|
||||||
any,
|
|
||||||
mem,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
use glutin;
|
use glutin;
|
||||||
use failure;
|
use failure;
|
||||||
|
use log;
|
||||||
|
use pretty_env_logger;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
menu::title::TitleState,
|
menu::title::TitleState,
|
||||||
window::Window,
|
window::Window,
|
||||||
render::RenderErr,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum VoxygenErr {
|
|
||||||
BackendErr(Box<any::Any>),
|
|
||||||
RenderErr(RenderErr),
|
|
||||||
Other(failure::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RenderErr> for VoxygenErr {
|
|
||||||
fn from(err: RenderErr) -> Self {
|
|
||||||
VoxygenErr::RenderErr(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A type used to store state that is shared between all play states
|
// A type used to store state that is shared between all play states
|
||||||
pub struct GlobalState {
|
pub struct GlobalState {
|
||||||
window: Window,
|
window: Window,
|
||||||
@ -42,40 +33,73 @@ pub struct GlobalState {
|
|||||||
pub enum PlayStateResult {
|
pub enum PlayStateResult {
|
||||||
/// Pop all play states in reverse order and shut down the program
|
/// Pop all play states in reverse order and shut down the program
|
||||||
Shutdown,
|
Shutdown,
|
||||||
/// Close the current play state
|
/// Close the current play state and pop it from the play state stack
|
||||||
Close,
|
Pop,
|
||||||
/// Push a new play state onto the play state stack
|
/// Push a new play state onto the play state stack
|
||||||
Push(Box<dyn PlayState>),
|
Push(Box<dyn PlayState>),
|
||||||
/// Switch the current play state with a new play state
|
/// Switch the current play state with a new play state
|
||||||
Switch(Box<dyn PlayState>),
|
Switch(Box<dyn PlayState>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait representing a playable game state. This may be a menu, a game session, the title
|
||||||
|
/// screen, etc.
|
||||||
pub trait PlayState {
|
pub trait PlayState {
|
||||||
|
/// Play the state until some change of state is required (i.e: a menu is opened or the game
|
||||||
|
/// is closed).
|
||||||
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult;
|
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult;
|
||||||
|
|
||||||
|
/// Get a descriptive name for this state type
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(TitleState::new())];
|
// Init logging
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
// Set up the initial play state
|
||||||
|
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(TitleState::new())];
|
||||||
|
states.last().map(|current_state| {
|
||||||
|
log::info!("Started game with state '{}'", current_state.name())
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up the global state
|
||||||
let mut global_state = GlobalState {
|
let mut global_state = GlobalState {
|
||||||
window: Window::new()
|
window: Window::new()
|
||||||
.expect("Failed to create window"),
|
.expect("Failed to create window"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// What's going on here?
|
||||||
|
// ---------------------
|
||||||
|
// The state system used by Voxygen allows for the easy development of stack-based menus.
|
||||||
|
// For example, you may want a "title" state that can push a "main menu" state on top of it,
|
||||||
|
// which can in turn push a "settings" state or a "game session" state on top of it.
|
||||||
|
// The code below manages the state transfer logic automatically so that we don't have to
|
||||||
|
// re-engineer it for each menu we decide to add to the game.
|
||||||
while let Some(state_result) = states.last_mut().map(|last| last.play(&mut global_state)){
|
while let Some(state_result) = states.last_mut().map(|last| last.play(&mut global_state)){
|
||||||
// Implement state transfer logic
|
// Implement state transfer logic
|
||||||
match state_result {
|
match state_result {
|
||||||
PlayStateResult::Shutdown => while states.last().is_some() {
|
PlayStateResult::Shutdown => {
|
||||||
states.pop();
|
log::info!("Shutting down all states...");
|
||||||
|
while states.last().is_some() {
|
||||||
|
states.pop().map(|old_state| {
|
||||||
|
log::info!("Popped state '{}'", old_state.name())
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
PlayStateResult::Close => {
|
PlayStateResult::Pop => {
|
||||||
states.pop();
|
states.pop().map(|old_state| {
|
||||||
|
log::info!("Popped state '{}'", old_state.name())
|
||||||
|
});
|
||||||
},
|
},
|
||||||
PlayStateResult::Push(new_state) => {
|
PlayStateResult::Push(new_state) => {
|
||||||
|
log::info!("Pushed state '{}'", new_state.name());
|
||||||
states.push(new_state);
|
states.push(new_state);
|
||||||
},
|
},
|
||||||
PlayStateResult::Switch(mut new_state) => {
|
PlayStateResult::Switch(mut new_state) => {
|
||||||
states.last_mut().map(|old_state| mem::swap(old_state, &mut new_state));
|
states.last_mut().map(|old_state| {
|
||||||
|
log::info!("Switching to state '{}' from state '{}'", new_state.name(), old_state.name());
|
||||||
|
mem::swap(old_state, &mut new_state);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,32 +7,47 @@ use crate::{
|
|||||||
PlayStateResult,
|
PlayStateResult,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
window::Event,
|
window::Event,
|
||||||
|
render,
|
||||||
|
session::SessionState,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TitleState;
|
pub struct TitleState;
|
||||||
|
|
||||||
impl TitleState {
|
impl TitleState {
|
||||||
|
/// Create a new `TitleState`
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BG_COLOR: Rgba<f32> = Rgba { r: 0.0, g: 0.3, b: 1.0, a: 1.0 };
|
// The background colour
|
||||||
|
const BG_COLOR: Rgba<f32> = Rgba { r: 0.8, g: 1.0, b: 0.8, a: 1.0 };
|
||||||
|
|
||||||
impl PlayState for TitleState {
|
impl PlayState for TitleState {
|
||||||
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
|
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
|
||||||
'eventloop: loop {
|
loop {
|
||||||
// Process window events
|
// Handle window events
|
||||||
for event in global_state.window.fetch_events() {
|
for event in global_state.window.fetch_events() {
|
||||||
match event {
|
match event {
|
||||||
Event::Close => break 'eventloop PlayStateResult::Shutdown,
|
Event::Close => return PlayStateResult::Shutdown,
|
||||||
|
// When space is pressed, start a session
|
||||||
|
Event::Char(' ') => return PlayStateResult::Push(
|
||||||
|
Box::new(SessionState::from_renderer(global_state.window.renderer_mut())),
|
||||||
|
),
|
||||||
|
// Ignore all other events
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
global_state.window.renderer_mut().clear(BG_COLOR);
|
global_state.window.renderer_mut().clear(BG_COLOR);
|
||||||
|
|
||||||
|
// Finish the frame
|
||||||
global_state.window.renderer_mut().flush();
|
global_state.window.renderer_mut().flush();
|
||||||
global_state.window.display()
|
global_state.window.display()
|
||||||
.expect("Failed to display window");
|
.expect("Failed to display window");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &'static str { "Title" }
|
||||||
}
|
}
|
||||||
|
@ -6,28 +6,32 @@ use gfx::{
|
|||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{
|
||||||
RenderErr,
|
RenderError,
|
||||||
gfx_backend,
|
gfx_backend,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A handle to a series of constants sitting on the GPU. This is used to hold information used in
|
||||||
|
/// the rendering process that does not change throughout a single render pass.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Consts<T: Copy + gfx::traits::Pod> {
|
pub struct Consts<T: Copy + gfx::traits::Pod> {
|
||||||
pub buf: gfx::handle::Buffer<gfx_backend::Resources, T>,
|
pub buf: gfx::handle::Buffer<gfx_backend::Resources, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
||||||
|
/// Create a new `Const<T>`
|
||||||
pub fn new(factory: &mut gfx_backend::Factory) -> Self {
|
pub fn new(factory: &mut gfx_backend::Factory) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buf: factory.create_constant_buffer(1),
|
buf: factory.create_constant_buffer(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the GPU-side value represented by this constant handle.
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
data: T,
|
val: T,
|
||||||
) -> Result<(), RenderErr> {
|
) -> Result<(), RenderError> {
|
||||||
encoder.update_buffer(&self.buf, &[data], 0)
|
encoder.update_buffer(&self.buf, &[val], 0)
|
||||||
.map_err(|err| RenderErr::UpdateErr(err))
|
.map_err(|err| RenderError::UpdateError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,38 @@
|
|||||||
// Local
|
// Local
|
||||||
use super::Pipeline;
|
use super::Pipeline;
|
||||||
|
|
||||||
/// Used to store vertex data on the CPU
|
/// A `Vec`-based mesh structure used to store mesh data on the CPU.
|
||||||
pub struct Mesh<P: Pipeline> {
|
pub struct Mesh<P: Pipeline> {
|
||||||
verts: Vec<P::Vertex>,
|
verts: Vec<P::Vertex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Pipeline> Mesh<P> {
|
impl<P: Pipeline> Mesh<P> {
|
||||||
|
/// Create a new `Mesh`
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { verts: vec![] }
|
Self { verts: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a slice referencing the vertices of this mesh.
|
||||||
pub fn vertices(&self) -> &[P::Vertex] {
|
pub fn vertices(&self) -> &[P::Vertex] {
|
||||||
&self.verts
|
&self.verts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push a new vertex onto the end of this mesh.
|
||||||
pub fn push(&mut self, vert: P::Vertex) {
|
pub fn push(&mut self, vert: P::Vertex) {
|
||||||
self.verts.push(vert);
|
self.verts.push(vert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push a new polygon onto the end of this mesh.
|
||||||
|
pub fn push_tri(&mut self, tri: Tri<P>) {
|
||||||
|
self.verts.push(tri.a);
|
||||||
|
self.verts.push(tri.b);
|
||||||
|
self.verts.push(tri.c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push a new quad onto the end of this mesh.
|
||||||
pub fn push_quad(&mut self, quad: Quad<P>) {
|
pub fn push_quad(&mut self, quad: Quad<P>) {
|
||||||
|
// A quad is composed of two triangles. The code below converts the former to the latter.
|
||||||
|
|
||||||
// Tri 1
|
// Tri 1
|
||||||
self.verts.push(quad.a.clone());
|
self.verts.push(quad.a.clone());
|
||||||
self.verts.push(quad.b);
|
self.verts.push(quad.b);
|
||||||
@ -32,7 +45,24 @@ impl<P: Pipeline> Mesh<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a quad
|
/// Represents a triangle stored on the CPU.
|
||||||
|
pub struct Tri<P: Pipeline> {
|
||||||
|
a: P::Vertex,
|
||||||
|
b: P::Vertex,
|
||||||
|
c: P::Vertex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pipeline> Tri<P> {
|
||||||
|
pub fn new(
|
||||||
|
a: P::Vertex,
|
||||||
|
b: P::Vertex,
|
||||||
|
c: P::Vertex,
|
||||||
|
) -> Self {
|
||||||
|
Self { a, b, c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a quad stored on the CPU.
|
||||||
pub struct Quad<P: Pipeline> {
|
pub struct Quad<P: Pipeline> {
|
||||||
a: P::Vertex,
|
a: P::Vertex,
|
||||||
b: P::Vertex,
|
b: P::Vertex,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
mod consts;
|
pub mod consts;
|
||||||
mod mesh;
|
pub mod mesh;
|
||||||
mod model;
|
pub mod model;
|
||||||
mod pipelines;
|
pub mod pipelines;
|
||||||
mod renderer;
|
pub mod renderer;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
@ -11,8 +11,16 @@ pub use self::{
|
|||||||
model::Model,
|
model::Model,
|
||||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
character::CharacterPipeline,
|
Globals,
|
||||||
skybox::SkyboxPipeline,
|
character::{
|
||||||
|
CharacterPipeline,
|
||||||
|
Locals as CharacterLocals,
|
||||||
|
},
|
||||||
|
skybox::{
|
||||||
|
create_mesh as create_skybox_mesh,
|
||||||
|
SkyboxPipeline,
|
||||||
|
Locals as SkyboxLocals,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,9 +32,9 @@ use gfx;
|
|||||||
|
|
||||||
/// Used to represent one of many possible errors that may be omitted by the rendering code
|
/// Used to represent one of many possible errors that may be omitted by the rendering code
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RenderErr {
|
pub enum RenderError {
|
||||||
PipelineErr(gfx::PipelineStateError<String>),
|
PipelineError(gfx::PipelineStateError<String>),
|
||||||
UpdateErr(gfx::UpdateError<usize>),
|
UpdateError(gfx::UpdateError<usize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to represent a specific rendering configuration
|
/// Used to represent a specific rendering configuration
|
||||||
|
@ -11,7 +11,7 @@ use super::{
|
|||||||
gfx_backend,
|
gfx_backend,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents a mesh that has been sent to the CPU
|
/// Represents a mesh that has been sent to the GPU.
|
||||||
pub struct Model<P: Pipeline> {
|
pub struct Model<P: Pipeline> {
|
||||||
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
|
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
|
||||||
pub slice: gfx::Slice<gfx_backend::Resources>,
|
pub slice: gfx::Slice<gfx_backend::Resources>,
|
||||||
|
@ -23,6 +23,7 @@ use super::{
|
|||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
vertex Vertex {
|
vertex Vertex {
|
||||||
pos: [f32; 3] = "v_pos",
|
pos: [f32; 3] = "v_pos",
|
||||||
|
col: [f32; 3] = "v_col",
|
||||||
bone: u8 = "v_bone",
|
bone: u8 = "v_bone",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,10 @@ use gfx::{
|
|||||||
self,
|
self,
|
||||||
// Macros
|
// Macros
|
||||||
gfx_defines,
|
gfx_defines,
|
||||||
gfx_vertex_struct_meta,
|
|
||||||
gfx_constant_struct_meta,
|
gfx_constant_struct_meta,
|
||||||
gfx_impl_struct_meta,
|
gfx_impl_struct_meta,
|
||||||
gfx_pipeline,
|
|
||||||
gfx_pipeline_inner,
|
|
||||||
};
|
};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
gfx_defines! {
|
gfx_defines! {
|
||||||
constant Globals {
|
constant Globals {
|
||||||
@ -24,3 +22,28 @@ gfx_defines! {
|
|||||||
time: [f32; 4] = "time",
|
time: [f32; 4] = "time",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Globals {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
// TODO: Get rid of this ugliness
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn f32_arr_to_mat(arr: [f32; 16]) -> [[f32; 4]; 4] {
|
||||||
|
[
|
||||||
|
[arr[ 0], arr[ 1], arr[ 2], arr[ 3]],
|
||||||
|
[arr[ 4], arr[ 5], arr[ 6], arr[ 7]],
|
||||||
|
[arr[ 8], arr[ 9], arr[10], arr[11]],
|
||||||
|
[arr[12], arr[13], arr[14], arr[15]],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
view_mat: f32_arr_to_mat(Mat4::identity().into_col_array()),
|
||||||
|
proj_mat: f32_arr_to_mat(Mat4::identity().into_col_array()),
|
||||||
|
cam_pos: [0.0; 4],
|
||||||
|
focus_pos: [0.0; 4],
|
||||||
|
view_distance: [0.0; 4],
|
||||||
|
tod: [0.0; 4],
|
||||||
|
time: [0.0; 4],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -28,7 +28,7 @@ gfx_defines! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constant Locals {
|
constant Locals {
|
||||||
model_mat: [[f32; 4]; 4] = "model_mat",
|
nul: [f32; 4] = "nul",
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline pipe {
|
pipeline pipe {
|
||||||
@ -36,7 +36,13 @@ gfx_defines! {
|
|||||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Locals {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { nul: [0.0; 4] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,16 +5,13 @@ use gfx::{
|
|||||||
traits::{Device, FactoryExt},
|
traits::{Device, FactoryExt},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Crate
|
|
||||||
use crate::VoxygenErr;
|
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use super::{
|
use super::{
|
||||||
consts::Consts,
|
consts::Consts,
|
||||||
model::Model,
|
model::Model,
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
Pipeline,
|
Pipeline,
|
||||||
RenderErr,
|
RenderError,
|
||||||
gfx_backend,
|
gfx_backend,
|
||||||
pipelines::{
|
pipelines::{
|
||||||
Globals,
|
Globals,
|
||||||
@ -23,12 +20,19 @@ use super::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents the format of the window's color target.
|
||||||
pub type TgtColorFmt = gfx::format::Srgba8;
|
pub type TgtColorFmt = gfx::format::Srgba8;
|
||||||
|
/// Represents the format of the window's depth target.
|
||||||
pub type TgtDepthFmt = gfx::format::DepthStencil;
|
pub type TgtDepthFmt = gfx::format::DepthStencil;
|
||||||
|
|
||||||
|
/// A handle to a window color target.
|
||||||
pub type TgtColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, TgtColorFmt>;
|
pub type TgtColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, TgtColorFmt>;
|
||||||
|
/// A handle to a window depth target.
|
||||||
pub type TgtDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, TgtDepthFmt>;
|
pub type TgtDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, TgtDepthFmt>;
|
||||||
|
|
||||||
|
/// A type that encapsulates rendering state. `Renderer` is central to Voxygen's rendering
|
||||||
|
/// subsystem and contains any state necessary to interact with the GPU, along with pipeline state
|
||||||
|
/// objects (PSOs) needed to renderer different kinds of model to the screen.
|
||||||
pub struct Renderer {
|
pub struct Renderer {
|
||||||
device: gfx_backend::Device,
|
device: gfx_backend::Device,
|
||||||
encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
@ -38,18 +42,19 @@ pub struct Renderer {
|
|||||||
tgt_depth_view: TgtDepthView,
|
tgt_depth_view: TgtDepthView,
|
||||||
|
|
||||||
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
||||||
//character_pipeline: GfxPipeline<character::pipe::Init<'static>>,
|
character_pipeline: GfxPipeline<character::pipe::Init<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
|
/// Create a new `Renderer` from a variety of backend-specific components and the window targets.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: gfx_backend::Device,
|
device: gfx_backend::Device,
|
||||||
mut factory: gfx_backend::Factory,
|
mut factory: gfx_backend::Factory,
|
||||||
tgt_color_view: TgtColorView,
|
tgt_color_view: TgtColorView,
|
||||||
tgt_depth_view: TgtDepthView,
|
tgt_depth_view: TgtDepthView,
|
||||||
) -> Result<Self, RenderErr> {
|
) -> Result<Self, RenderError> {
|
||||||
// Construct a pipeline for rendering skyboxes
|
// Construct a pipeline for rendering skyboxes
|
||||||
let skybox_pipeline = Self::create_pipeline(
|
let skybox_pipeline = create_pipeline(
|
||||||
&mut factory,
|
&mut factory,
|
||||||
skybox::pipe::new(),
|
skybox::pipe::new(),
|
||||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.vert")),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.vert")),
|
||||||
@ -57,14 +62,12 @@ impl Renderer {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering characters
|
// Construct a pipeline for rendering characters
|
||||||
/*
|
let character_pipeline = create_pipeline(
|
||||||
let character_pipeline = Self::new_pipeline(
|
|
||||||
&mut factory,
|
&mut factory,
|
||||||
character::pipe::new(),
|
character::pipe::new(),
|
||||||
include_bytes!("shaders/character.vert"),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/character.vert")),
|
||||||
include_bytes!("shaders/character.frag"),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/character.frag")),
|
||||||
)?;
|
)?;
|
||||||
*/
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
device,
|
device,
|
||||||
@ -75,57 +78,36 @@ impl Renderer {
|
|||||||
tgt_depth_view,
|
tgt_depth_view,
|
||||||
|
|
||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
//character_pipeline,
|
character_pipeline,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queue the clearing of the color and depth targets ready for a new frame to be rendered.
|
||||||
pub fn clear(&mut self, col: Rgba<f32>) {
|
pub fn clear(&mut self, col: Rgba<f32>) {
|
||||||
self.encoder.clear(&self.tgt_color_view, col.into_array());
|
self.encoder.clear(&self.tgt_color_view, col.into_array());
|
||||||
self.encoder.clear_depth(&self.tgt_depth_view, 1.0);
|
self.encoder.clear_depth(&self.tgt_depth_view, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform all queued draw calls for this frame and clean up discarded items
|
/// Perform all queued draw calls for this frame and clean up discarded items.
|
||||||
pub fn flush(&mut self) {
|
pub fn flush(&mut self) {
|
||||||
self.encoder.flush(&mut self.device);
|
self.encoder.flush(&mut self.device);
|
||||||
self.device.cleanup();
|
self.device.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new pipeline from the provided vertex shader and fragment shader
|
/// Create a new set of constants.
|
||||||
fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
pub fn create_consts<T: Copy + gfx::traits::Pod>(&mut self) -> Result<Consts<T>, RenderError> {
|
||||||
factory: &mut gfx_backend::Factory,
|
Ok(Consts::new(&mut self.factory))
|
||||||
pipe: P,
|
|
||||||
vs: &[u8],
|
|
||||||
fs: &[u8],
|
|
||||||
) -> Result<GfxPipeline<P>, RenderErr> {
|
|
||||||
let program = factory
|
|
||||||
.link_program(vs, fs)
|
|
||||||
.map_err(|err| RenderErr::PipelineErr(gfx::PipelineStateError::Program(err)))?;
|
|
||||||
|
|
||||||
Ok(GfxPipeline {
|
|
||||||
pso: factory.create_pipeline_from_program(
|
|
||||||
&program,
|
|
||||||
gfx::Primitive::TriangleList,
|
|
||||||
gfx::state::Rasterizer {
|
|
||||||
front_face: gfx::state::FrontFace::CounterClockwise,
|
|
||||||
cull_face: gfx::state::CullFace::Back,
|
|
||||||
method: gfx::state::RasterMethod::Fill,
|
|
||||||
offset: None,
|
|
||||||
samples: Some(gfx::state::MultiSample),
|
|
||||||
},
|
|
||||||
pipe,
|
|
||||||
)
|
|
||||||
// Do some funky things to work around an oddity in gfx's error ownership rules
|
|
||||||
.map_err(|err| RenderErr::PipelineErr(match err {
|
|
||||||
gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err),
|
|
||||||
gfx::PipelineStateError::DescriptorInit(err) => gfx::PipelineStateError::DescriptorInit(err.into()),
|
|
||||||
gfx::PipelineStateError::DeviceCreate(err) => gfx::PipelineStateError::DeviceCreate(err),
|
|
||||||
}))?,
|
|
||||||
program,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new model from the provided mesh
|
/// Create a new set of constants and update then with a value.
|
||||||
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderErr> {
|
pub fn create_consts_with<T: Copy + gfx::traits::Pod>(&mut self, val: T) -> Result<Consts<T>, RenderError> {
|
||||||
|
let mut consts = self.create_consts()?;
|
||||||
|
consts.update(&mut self.encoder, val)?;
|
||||||
|
Ok(consts)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new model from the provided mesh.
|
||||||
|
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
||||||
Ok(Model::new(
|
Ok(Model::new(
|
||||||
&mut self.factory,
|
&mut self.factory,
|
||||||
mesh,
|
mesh,
|
||||||
@ -153,7 +135,41 @@ impl Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GfxPipeline<P: gfx::pso::PipelineInit> {
|
struct GfxPipeline<P: gfx::pso::PipelineInit> {
|
||||||
program: gfx::handle::Program<gfx_backend::Resources>,
|
program: gfx::handle::Program<gfx_backend::Resources>,
|
||||||
pso: gfx::pso::PipelineState<gfx_backend::Resources, P::Meta>,
|
pso: gfx::pso::PipelineState<gfx_backend::Resources, P::Meta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new pipeline from the provided vertex shader and fragment shader
|
||||||
|
fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
||||||
|
factory: &mut gfx_backend::Factory,
|
||||||
|
pipe: P,
|
||||||
|
vs: &[u8],
|
||||||
|
fs: &[u8],
|
||||||
|
) -> Result<GfxPipeline<P>, RenderError> {
|
||||||
|
let program = factory
|
||||||
|
.link_program(vs, fs)
|
||||||
|
.map_err(|err| RenderError::PipelineError(gfx::PipelineStateError::Program(err)))?;
|
||||||
|
|
||||||
|
Ok(GfxPipeline {
|
||||||
|
pso: factory.create_pipeline_from_program(
|
||||||
|
&program,
|
||||||
|
gfx::Primitive::TriangleList,
|
||||||
|
gfx::state::Rasterizer {
|
||||||
|
front_face: gfx::state::FrontFace::CounterClockwise,
|
||||||
|
cull_face: gfx::state::CullFace::Back,
|
||||||
|
method: gfx::state::RasterMethod::Fill,
|
||||||
|
offset: None,
|
||||||
|
samples: Some(gfx::state::MultiSample),
|
||||||
|
},
|
||||||
|
pipe,
|
||||||
|
)
|
||||||
|
// Do some funky things to work around an oddity in gfx's error ownership rules
|
||||||
|
.map_err(|err| RenderError::PipelineError(match err {
|
||||||
|
gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err),
|
||||||
|
gfx::PipelineStateError::DescriptorInit(err) => gfx::PipelineStateError::DescriptorInit(err.into()),
|
||||||
|
gfx::PipelineStateError::DeviceCreate(err) => gfx::PipelineStateError::DeviceCreate(err),
|
||||||
|
}))?,
|
||||||
|
program,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
49
voxygen/src/scene/camera.rs
Normal file
49
voxygen/src/scene/camera.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Standard
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
const NEAR_PLANE: f32 = 0.1;
|
||||||
|
const FAR_PLANE: f32 = 10000.0;
|
||||||
|
|
||||||
|
pub struct Camera {
|
||||||
|
focus: Vec3<f32>,
|
||||||
|
ori: Vec3<f32>,
|
||||||
|
dist: f32,
|
||||||
|
fov: f32,
|
||||||
|
aspect: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Camera {
|
||||||
|
/// Create a new `Camera` with default parameters.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
focus: Vec3::zero(),
|
||||||
|
ori: Vec3::zero(),
|
||||||
|
dist: 10.0,
|
||||||
|
fov: 1.3,
|
||||||
|
aspect: 1.618,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the transformation matrices (view matrix and projection matrix) for the camera.
|
||||||
|
pub fn compute_matrices(&self) -> (Mat4<f32>, Mat4<f32>) {
|
||||||
|
let view = Mat4::<f32>::identity()
|
||||||
|
* Mat4::translation_3d(-Vec3::unit_z() * self.dist)
|
||||||
|
* Mat4::rotation_z(self.ori.z)
|
||||||
|
* Mat4::rotation_x(self.ori.y)
|
||||||
|
* Mat4::rotation_y(self.ori.x)
|
||||||
|
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
|
||||||
|
* Mat4::translation_3d(-self.focus);
|
||||||
|
|
||||||
|
let proj = Mat4::perspective_rh_no(
|
||||||
|
self.fov,
|
||||||
|
self.aspect,
|
||||||
|
NEAR_PLANE,
|
||||||
|
FAR_PLANE,
|
||||||
|
);
|
||||||
|
|
||||||
|
(view, proj)
|
||||||
|
}
|
||||||
|
}
|
56
voxygen/src/scene/mod.rs
Normal file
56
voxygen/src/scene/mod.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
pub mod camera;
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::render::{
|
||||||
|
Consts,
|
||||||
|
Globals,
|
||||||
|
Model,
|
||||||
|
Renderer,
|
||||||
|
SkyboxPipeline,
|
||||||
|
SkyboxLocals,
|
||||||
|
create_skybox_mesh,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Local
|
||||||
|
use self::camera::Camera;
|
||||||
|
|
||||||
|
struct Skybox {
|
||||||
|
model: Model<SkyboxPipeline>,
|
||||||
|
locals: Consts<SkyboxLocals>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Scene {
|
||||||
|
camera: Camera,
|
||||||
|
globals: Consts<Globals>,
|
||||||
|
skybox: Skybox,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
/// Create a new `Scene` with default parameters.
|
||||||
|
pub fn new(renderer: &mut Renderer) -> Self {
|
||||||
|
Self {
|
||||||
|
camera: Camera::new(),
|
||||||
|
globals: renderer
|
||||||
|
.create_consts_with(Globals::new())
|
||||||
|
.unwrap(),
|
||||||
|
skybox: Skybox {
|
||||||
|
model: renderer
|
||||||
|
.create_model(&create_skybox_mesh())
|
||||||
|
.unwrap(),
|
||||||
|
locals: renderer
|
||||||
|
.create_consts_with(SkyboxLocals::new())
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render the scene using the provided `Renderer`
|
||||||
|
pub fn render_to(&self, renderer: &mut Renderer) {
|
||||||
|
// Render the skybox first (it appears over everything else so must be rendered first)
|
||||||
|
renderer.render_skybox(
|
||||||
|
&self.skybox.model,
|
||||||
|
&self.skybox.locals,
|
||||||
|
&self.globals,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
61
voxygen/src/session.rs
Normal file
61
voxygen/src/session.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::{
|
||||||
|
PlayState,
|
||||||
|
PlayStateResult,
|
||||||
|
GlobalState,
|
||||||
|
window::Event,
|
||||||
|
render::Renderer,
|
||||||
|
scene::Scene,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SessionState {
|
||||||
|
scene: Scene,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents an active game session (i.e: one that is being played)
|
||||||
|
impl SessionState {
|
||||||
|
/// Create a new `SessionState`
|
||||||
|
pub fn from_renderer(renderer: &mut Renderer) -> Self {
|
||||||
|
Self {
|
||||||
|
// Create a scene for this session. The scene handles visible elements of the game world
|
||||||
|
scene: Scene::new(renderer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The background colour
|
||||||
|
const BG_COLOR: Rgba<f32> = Rgba { r: 0.0, g: 0.3, b: 1.0, a: 1.0 };
|
||||||
|
|
||||||
|
impl PlayState for SessionState {
|
||||||
|
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
|
||||||
|
// Game loop
|
||||||
|
loop {
|
||||||
|
// Handle window events
|
||||||
|
for event in global_state.window.fetch_events() {
|
||||||
|
match event {
|
||||||
|
Event::Close => return PlayStateResult::Shutdown,
|
||||||
|
// When 'q' is pressed, exit the session
|
||||||
|
Event::Char('q') => return PlayStateResult::Pop,
|
||||||
|
// Ignore all other events
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the screen
|
||||||
|
global_state.window.renderer_mut().clear(BG_COLOR);
|
||||||
|
|
||||||
|
// Render the screen using the global renderer
|
||||||
|
self.scene.render_to(global_state.window.renderer_mut());
|
||||||
|
|
||||||
|
// Finish the frame
|
||||||
|
global_state.window.renderer_mut().flush();
|
||||||
|
global_state.window.display()
|
||||||
|
.expect("Failed to display window");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &'static str { "Session" }
|
||||||
|
}
|
@ -4,7 +4,7 @@ use gfx_window_glutin;
|
|||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
VoxygenErr,
|
Error,
|
||||||
render::{
|
render::{
|
||||||
Renderer,
|
Renderer,
|
||||||
TgtColorFmt,
|
TgtColorFmt,
|
||||||
@ -20,14 +20,13 @@ pub struct Window {
|
|||||||
|
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new() -> Result<Window, VoxygenErr> {
|
pub fn new() -> Result<Window, Error> {
|
||||||
let events_loop = glutin::EventsLoop::new();
|
let events_loop = glutin::EventsLoop::new();
|
||||||
|
|
||||||
let win_builder = glutin::WindowBuilder::new()
|
let win_builder = glutin::WindowBuilder::new()
|
||||||
.with_title("Veloren (Voxygen)")
|
.with_title("Veloren (Voxygen)")
|
||||||
.with_dimensions(glutin::dpi::LogicalSize::new(800.0, 500.0))
|
.with_dimensions(glutin::dpi::LogicalSize::new(800.0, 500.0))
|
||||||
.with_maximized(false)
|
.with_maximized(false);
|
||||||
;
|
|
||||||
|
|
||||||
let ctx_builder = glutin::ContextBuilder::new()
|
let ctx_builder = glutin::ContextBuilder::new()
|
||||||
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
||||||
@ -43,7 +42,7 @@ impl Window {
|
|||||||
win_builder,
|
win_builder,
|
||||||
ctx_builder,
|
ctx_builder,
|
||||||
&events_loop,
|
&events_loop,
|
||||||
).map_err(|err| VoxygenErr::BackendErr(Box::new(err)))?;
|
).map_err(|err| Error::BackendError(Box::new(err)))?;
|
||||||
|
|
||||||
let tmp = Ok(Self {
|
let tmp = Ok(Self {
|
||||||
events_loop,
|
events_loop,
|
||||||
@ -66,6 +65,7 @@ impl Window {
|
|||||||
self.events_loop.poll_events(|event| match event {
|
self.events_loop.poll_events(|event| match event {
|
||||||
glutin::Event::WindowEvent { event, .. } => match event {
|
glutin::Event::WindowEvent { event, .. } => match event {
|
||||||
glutin::WindowEvent::CloseRequested => events.push(Event::Close),
|
glutin::WindowEvent::CloseRequested => events.push(Event::Close),
|
||||||
|
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -73,12 +73,13 @@ impl Window {
|
|||||||
events
|
events
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display(&self) -> Result<(), VoxygenErr> {
|
pub fn display(&self) -> Result<(), Error> {
|
||||||
self.window.swap_buffers()
|
self.window.swap_buffers()
|
||||||
.map_err(|err| VoxygenErr::BackendErr(Box::new(err)))
|
.map_err(|err| Error::BackendError(Box::new(err)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Close,
|
Close,
|
||||||
|
Char(char),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user