Added pipeline components

This commit is contained in:
Joshua Barretto 2019-01-11 20:14:37 +00:00
parent d8c87984d5
commit d559d633ab
13 changed files with 423 additions and 59 deletions

View 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(1.0, 0.0, 0.0, 1.0);
}

View File

@ -0,0 +1,30 @@
#version 330 core
in vec3 v_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 vec3 f_pos;
void main() {
f_pos = v_pos;
gl_Position =
proj_mat *
view_mat *
vec4(3000 * v_pos + cam_pos.xyz, 1);
}

View File

@ -16,14 +16,22 @@ use failure;
use crate::{
menu::title::TitleState,
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
pub struct GlobalState {
window: Window,

View File

@ -17,6 +17,8 @@ impl TitleState {
}
}
const BG_COLOR: Rgba<f32> = Rgba { r: 0.0, g: 0.3, b: 1.0, a: 1.0 };
impl PlayState for TitleState {
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
'eventloop: loop {
@ -27,12 +29,7 @@ impl PlayState for TitleState {
}
}
global_state.window.renderer_mut().clear(Rgba::new(
0.0,
0.3,
1.0,
1.0,
));
global_state.window.renderer_mut().clear(BG_COLOR);
global_state.window.renderer_mut().flush();
global_state.window.display()
.expect("Failed to display window");

View File

@ -0,0 +1,33 @@
// Library
use gfx::{
self,
traits::FactoryExt,
};
// Local
use super::{
RenderErr,
gfx_backend,
};
#[derive(Clone)]
pub struct Consts<T: Copy + gfx::traits::Pod> {
pub buf: gfx::handle::Buffer<gfx_backend::Resources, T>,
}
impl<T: Copy + gfx::traits::Pod> Consts<T> {
pub fn new(factory: &mut gfx_backend::Factory) -> Self {
Self {
buf: factory.create_constant_buffer(1),
}
}
pub fn update(
&mut self,
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
data: T,
) -> Result<(), RenderErr> {
encoder.update_buffer(&self.buf, &[data], 0)
.map_err(|err| RenderErr::UpdateErr(err))
}
}

View File

@ -7,15 +7,46 @@ pub struct Mesh<P: Pipeline> {
}
impl<P: Pipeline> Mesh<P> {
pub fn empty() -> Self {
pub fn new() -> Self {
Self { verts: vec![] }
}
pub fn verts(&self) -> &[P::Vertex] {
pub fn vertices(&self) -> &[P::Vertex] {
&self.verts
}
pub fn push(&mut self, vert: P::Vertex) {
self.verts.push(vert);
}
pub fn push_quad(&mut self, quad: Quad<P>) {
// Tri 1
self.verts.push(quad.a.clone());
self.verts.push(quad.b);
self.verts.push(quad.c.clone());
// Tri 2
self.verts.push(quad.c);
self.verts.push(quad.d);
self.verts.push(quad.a);
}
}
/// Represents a quad
pub struct Quad<P: Pipeline> {
a: P::Vertex,
b: P::Vertex,
c: P::Vertex,
d: P::Vertex,
}
impl<P: Pipeline> Quad<P> {
pub fn new(
a: P::Vertex,
b: P::Vertex,
c: P::Vertex,
d: P::Vertex,
) -> Self {
Self { a, b, c, d }
}
}

View File

@ -1,25 +1,38 @@
mod consts;
mod mesh;
mod model;
mod renderer;
mod pipelines;
mod shader_set;
mod renderer;
// Reexports
pub use self::{
mesh::Mesh,
consts::Consts,
mesh::{Mesh, Quad},
model::Model,
shader_set::ShaderSet,
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
pipelines::{
character::CharacterPipeline,
skybox::SkyboxPipeline,
},
};
#[cfg(feature = "gl")]
use gfx_device_gl as gfx_backend;
// Library
use gfx;
/// Used to represent one of many possible errors that may be omitted by the rendering code
#[derive(Debug)]
pub enum RenderErr {}
pub enum RenderErr {
PipelineErr(gfx::PipelineStateError<String>),
UpdateErr(gfx::UpdateError<usize>),
}
/// Used to represent a specific rendering configuration
pub trait Pipeline {
type Vertex;
type Vertex:
Clone +
gfx::traits::Pod +
gfx::pso::buffer::Structure<gfx::format::Format>;
}

View File

@ -1,18 +1,36 @@
// Standard
use std::marker::PhantomData;
// Library
use gfx::{
self,
traits::FactoryExt,
};
// Local
use super::Pipeline;
use super::{
mesh::Mesh,
Pipeline,
gfx_backend,
};
/// Represents a mesh that has been sent to the CPU
pub struct Model<P: Pipeline> {
phantom: PhantomData<P>,
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
pub slice: gfx::Slice<gfx_backend::Resources>,
}
impl<P: Pipeline> Model<P> {
pub fn new() -> Self {
pub fn new(
factory: &mut gfx_backend::Factory,
mesh: &Mesh<P>,
) -> Self {
Self {
phantom: PhantomData,
vbuf: factory.create_vertex_buffer(mesh.vertices()),
slice: gfx::Slice {
start: 0,
end: mesh.vertices().len() as u32,
base_vertex: 0,
instances: None,
buffer: gfx::IndexBuffer::Auto,
},
}
}
}

View File

@ -1,11 +1,6 @@
// Library
use gfx::{
self,
VertexBuffer,
ConstantBuffer,
RenderTarget,
DepthTarget,
preset::depth::LESS_EQUAL_WRITE,
// Macros
gfx_defines,
gfx_vertex_struct_meta,
@ -16,8 +11,13 @@ use gfx::{
};
// Local
use super::super::{
renderer::{TgtColorFmt, TgtDepthFmt},
use super::{
Globals,
super::{
Pipeline,
TgtColorFmt,
TgtDepthFmt,
},
};
gfx_defines! {
@ -27,13 +27,20 @@ gfx_defines! {
}
constant Locals {
model: [[f32; 4]; 4] = "u_model",
model_mat: [[f32; 4]; 4] = "model_mat",
}
pipeline pipe {
vbuf: VertexBuffer<Vertex> = (),
locals: ConstantBuffer<Locals> = "locals",
tgt_color: RenderTarget<TgtColorFmt> = "tgt",
tgt_depth: DepthTarget<TgtDepthFmt> = LESS_EQUAL_WRITE,
vbuf: gfx::VertexBuffer<Vertex> = (),
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
}
}
pub struct CharacterPipeline;
impl Pipeline for CharacterPipeline {
type Vertex = Vertex;
}

View File

@ -1 +1,26 @@
mod character;
pub mod character;
pub mod skybox;
// Library
use gfx::{
self,
// Macros
gfx_defines,
gfx_vertex_struct_meta,
gfx_constant_struct_meta,
gfx_impl_struct_meta,
gfx_pipeline,
gfx_pipeline_inner,
};
gfx_defines! {
constant Globals {
view_mat: [[f32; 4]; 4] = "view_mat",
proj_mat: [[f32; 4]; 4] = "proj_mat",
cam_pos: [f32; 4] = "cam_pos",
focus_pos: [f32; 4] = "focus_pos",
view_distance: [f32; 4] = "view_distance",
tod: [f32; 4] = "tod",
time: [f32; 4] = "time",
}
}

View File

@ -0,0 +1,102 @@
// Library
use gfx::{
self,
// Macros
gfx_defines,
gfx_vertex_struct_meta,
gfx_constant_struct_meta,
gfx_impl_struct_meta,
gfx_pipeline,
gfx_pipeline_inner,
};
// Local
use super::{
Globals,
super::{
Pipeline,
TgtColorFmt,
TgtDepthFmt,
Mesh,
Quad,
},
};
gfx_defines! {
vertex Vertex {
pos: [f32; 3] = "v_pos",
}
constant Locals {
model_mat: [[f32; 4]; 4] = "model_mat",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
}
}
pub struct SkyboxPipeline;
impl Pipeline for SkyboxPipeline {
type Vertex = Vertex;
}
pub fn create_mesh() -> Mesh<SkyboxPipeline> {
let mut mesh = Mesh::new();
// -x
#[rustfmt::skip]
mesh.push_quad(Quad::new(
Vertex { pos: [-1.0, -1.0, -1.0] },
Vertex { pos: [-1.0, 1.0, -1.0] },
Vertex { pos: [-1.0, 1.0, 1.0] },
Vertex { pos: [-1.0, -1.0, 1.0] },
));
// +x
#[rustfmt::skip]
mesh.push_quad(Quad::new(
Vertex { pos: [ 1.0, -1.0, -1.0] },
Vertex { pos: [ 1.0, 1.0, 1.0] },
Vertex { pos: [ 1.0, 1.0, -1.0] },
Vertex { pos: [ 1.0, -1.0, 1.0] },
));
// -y
#[rustfmt::skip]
mesh.push_quad(Quad::new(
Vertex { pos: [ 1.0, -1.0, -1.0] },
Vertex { pos: [-1.0, -1.0, -1.0] },
Vertex { pos: [-1.0, -1.0, 1.0] },
Vertex { pos: [ 1.0, -1.0, 1.0] },
));
// +y
#[rustfmt::skip]
mesh.push_quad(Quad::new(
Vertex { pos: [ 1.0, 1.0, -1.0] },
Vertex { pos: [-1.0, 1.0, 1.0] },
Vertex { pos: [-1.0, 1.0, -1.0] },
Vertex { pos: [ 1.0, 1.0, 1.0] },
));
// -z
#[rustfmt::skip]
mesh.push_quad(Quad::new(
Vertex { pos: [-1.0, -1.0, -1.0] },
Vertex { pos: [ 1.0, -1.0, -1.0] },
Vertex { pos: [ 1.0, 1.0, -1.0] },
Vertex { pos: [-1.0, 1.0, -1.0] },
));
// +z
#[rustfmt::skip]
mesh.push_quad(Quad::new(
Vertex { pos: [-1.0, -1.0, 1.0] },
Vertex { pos: [ 1.0, 1.0, 1.0] },
Vertex { pos: [ 1.0, -1.0, 1.0] },
Vertex { pos: [-1.0, 1.0, 1.0] },
));
mesh
}

View File

@ -2,7 +2,7 @@
use vek::*;
use gfx::{
self,
traits::Device,
traits::{Device, FactoryExt},
};
// Crate
@ -10,12 +10,17 @@ use crate::VoxygenErr;
// Local
use super::{
consts::Consts,
model::Model,
mesh::Mesh,
shader_set::ShaderSet,
Pipeline,
RenderErr,
gfx_backend,
pipelines::{
Globals,
character,
skybox,
},
};
pub type TgtColorFmt = gfx::format::Srgba8;
@ -31,6 +36,9 @@ pub struct Renderer {
tgt_color_view: TgtColorView,
tgt_depth_view: TgtDepthView,
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
//character_pipeline: GfxPipeline<character::pipe::Init<'static>>,
}
impl Renderer {
@ -39,13 +47,35 @@ impl Renderer {
mut factory: gfx_backend::Factory,
tgt_color_view: TgtColorView,
tgt_depth_view: TgtDepthView,
) -> Result<Self, VoxygenErr> {
) -> Result<Self, RenderErr> {
// Construct a pipeline for rendering skyboxes
let skybox_pipeline = Self::create_pipeline(
&mut factory,
skybox::pipe::new(),
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.vert")),
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.frag")),
)?;
// Construct a pipeline for rendering characters
/*
let character_pipeline = Self::new_pipeline(
&mut factory,
character::pipe::new(),
include_bytes!("shaders/character.vert"),
include_bytes!("shaders/character.frag"),
)?;
*/
Ok(Self {
device,
encoder: factory.create_command_buffer().into(),
factory,
tgt_color_view,
tgt_depth_view,
skybox_pipeline,
//character_pipeline,
})
}
@ -54,8 +84,76 @@ impl Renderer {
self.encoder.clear_depth(&self.tgt_depth_view, 1.0);
}
/// Perform all queued draw calls for this frame and clean up discarded items
pub fn flush(&mut self) {
self.encoder.flush(&mut self.device);
self.device.cleanup();
}
/// 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>, 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
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderErr> {
Ok(Model::new(
&mut self.factory,
mesh,
))
}
/// Queue the rendering of the provided skybox model in the upcoming frame
pub fn render_skybox(
&mut self,
model: &Model<skybox::SkyboxPipeline>,
locals: &Consts<skybox::Locals>,
globals: &Consts<Globals>,
) {
self.encoder.draw(
&model.slice,
&self.skybox_pipeline.pso,
&skybox::pipe::Data {
vbuf: model.vbuf.clone(),
locals: locals.buf.clone(),
globals: globals.buf.clone(),
tgt_color: self.tgt_color_view.clone(),
tgt_depth: self.tgt_depth_view.clone(),
},
);
}
}
pub struct GfxPipeline<P: gfx::pso::PipelineInit> {
program: gfx::handle::Program<gfx_backend::Resources>,
pso: gfx::pso::PipelineState<gfx_backend::Resources, P::Meta>,
}

View File

@ -1,23 +0,0 @@
// Standard
use std::marker::PhantomData;
// Local
use super::{
Pipeline,
RenderErr
};
pub struct ShaderSet<P: Pipeline> {
phantom: PhantomData<P>,
}
impl<P: Pipeline> ShaderSet<P> {
pub fn new(
vs: &[u8],
fs: &[u8],
) -> Result<Self, RenderErr> {
Ok(Self {
phantom: PhantomData,
})
}
}