2019-01-07 21:10:31 +00:00
|
|
|
use super::{
|
2019-01-11 20:14:37 +00:00
|
|
|
consts::Consts,
|
2019-04-29 20:37:19 +00:00
|
|
|
gfx_backend,
|
2019-01-07 21:10:31 +00:00
|
|
|
mesh::Mesh,
|
2019-05-04 14:28:21 +00:00
|
|
|
model::{DynamicModel, Model},
|
2019-08-14 21:28:37 +00:00
|
|
|
pipelines::{figure, fluid, postprocess, skybox, terrain, ui, Globals, Light},
|
2019-01-30 12:11:34 +00:00
|
|
|
texture::Texture,
|
2019-04-29 20:37:19 +00:00
|
|
|
Pipeline, RenderError,
|
2019-01-07 21:10:31 +00:00
|
|
|
};
|
2019-08-03 05:42:33 +00:00
|
|
|
use common::assets::{self, watch::ReloadIndicator};
|
2019-04-29 20:37:19 +00:00
|
|
|
use gfx::{
|
|
|
|
self,
|
2019-05-06 08:22:47 +00:00
|
|
|
handle::Sampler,
|
|
|
|
traits::{Device, Factory, FactoryExt},
|
2019-04-29 20:37:19 +00:00
|
|
|
};
|
2019-05-12 09:10:13 +00:00
|
|
|
use glsl_include::Context as IncludeContext;
|
2019-08-03 05:42:33 +00:00
|
|
|
use log::error;
|
2019-04-29 20:37:19 +00:00
|
|
|
use vek::*;
|
2019-01-07 21:10:31 +00:00
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
/// Represents the format of the pre-processed color target.
|
2019-08-04 19:54:08 +00:00
|
|
|
pub type TgtColorFmt = gfx::format::Srgba8;
|
2019-05-06 16:27:21 +00:00
|
|
|
/// Represents the format of the pre-processed depth target.
|
2019-08-03 09:55:45 +00:00
|
|
|
pub type TgtDepthFmt = gfx::format::Depth;
|
2019-05-06 16:27:21 +00:00
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Represents the format of the window's color target.
|
2019-08-12 01:53:48 +00:00
|
|
|
pub type WinColorFmt = gfx::format::Srgba8;
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Represents the format of the window's depth target.
|
2019-08-03 09:55:45 +00:00
|
|
|
pub type WinDepthFmt = gfx::format::Depth;
|
2019-01-07 21:10:31 +00:00
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
/// A handle to a pre-processed color target.
|
2019-01-11 17:30:13 +00:00
|
|
|
pub type TgtColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, TgtColorFmt>;
|
2019-05-06 16:27:21 +00:00
|
|
|
/// A handle to a pre-processed depth target.
|
2019-01-11 17:30:13 +00:00
|
|
|
pub type TgtDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, TgtDepthFmt>;
|
2019-01-07 21:10:31 +00:00
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
/// A handle to a window color target.
|
|
|
|
pub type WinColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, WinColorFmt>;
|
|
|
|
/// A handle to a window depth target.
|
|
|
|
pub type WinDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, WinDepthFmt>;
|
|
|
|
|
2019-05-06 08:22:47 +00:00
|
|
|
/// A handle to a render color target as a resource.
|
|
|
|
pub type TgtColorRes = gfx::handle::ShaderResourceView<
|
|
|
|
gfx_backend::Resources,
|
|
|
|
<TgtColorFmt as gfx::format::Formatted>::View,
|
|
|
|
>;
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
/// 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
|
2019-01-12 13:56:34 +00:00
|
|
|
/// objects (PSOs) needed to renderer different kinds of models to the screen.
|
2019-01-07 21:10:31 +00:00
|
|
|
pub struct Renderer {
|
2019-01-11 17:30:13 +00:00
|
|
|
device: gfx_backend::Device,
|
|
|
|
encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
|
|
|
factory: gfx_backend::Factory,
|
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
win_color_view: WinColorView,
|
|
|
|
win_depth_view: WinDepthView,
|
2019-05-06 08:22:47 +00:00
|
|
|
|
2019-01-11 17:30:13 +00:00
|
|
|
tgt_color_view: TgtColorView,
|
|
|
|
tgt_depth_view: TgtDepthView,
|
2019-01-11 20:14:37 +00:00
|
|
|
|
2019-05-06 08:22:47 +00:00
|
|
|
tgt_color_res: TgtColorRes,
|
|
|
|
|
|
|
|
sampler: Sampler<gfx_backend::Resources>,
|
|
|
|
|
2019-01-11 20:14:37 +00:00
|
|
|
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
2019-01-13 20:53:55 +00:00
|
|
|
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
2019-01-14 23:13:58 +00:00
|
|
|
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
|
2019-08-14 21:28:37 +00:00
|
|
|
fluid_pipeline: GfxPipeline<fluid::pipe::Init<'static>>,
|
2019-01-30 12:11:34 +00:00
|
|
|
ui_pipeline: GfxPipeline<ui::pipe::Init<'static>>,
|
2019-05-06 08:22:47 +00:00
|
|
|
postprocess_pipeline: GfxPipeline<postprocess::pipe::Init<'static>>,
|
2019-08-03 05:42:33 +00:00
|
|
|
|
|
|
|
shader_reload_indicator: ReloadIndicator,
|
2019-01-07 21:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Renderer {
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Create a new `Renderer` from a variety of backend-specific components and the window targets.
|
2019-01-07 21:10:31 +00:00
|
|
|
pub fn new(
|
2019-01-11 17:30:13 +00:00
|
|
|
device: gfx_backend::Device,
|
|
|
|
mut factory: gfx_backend::Factory,
|
2019-05-06 16:27:21 +00:00
|
|
|
win_color_view: WinColorView,
|
|
|
|
win_depth_view: WinDepthView,
|
2019-01-11 23:18:34 +00:00
|
|
|
) -> Result<Self, RenderError> {
|
2019-08-03 05:42:33 +00:00
|
|
|
let mut shader_reload_indicator = ReloadIndicator::new();
|
|
|
|
|
2019-08-17 17:07:25 +00:00
|
|
|
let (
|
|
|
|
skybox_pipeline,
|
|
|
|
figure_pipeline,
|
|
|
|
terrain_pipeline,
|
|
|
|
fluid_pipeline,
|
|
|
|
ui_pipeline,
|
|
|
|
postprocess_pipeline,
|
|
|
|
) = create_pipelines(&mut factory, &mut shader_reload_indicator)?;
|
2019-05-06 08:22:47 +00:00
|
|
|
|
|
|
|
let dims = win_color_view.get_dimensions();
|
2019-05-06 12:03:15 +00:00
|
|
|
let (tgt_color_view, tgt_depth_view, tgt_color_res) =
|
|
|
|
Self::create_rt_views(&mut factory, (dims.0, dims.1))?;
|
2019-05-06 08:22:47 +00:00
|
|
|
|
|
|
|
let sampler = factory.create_sampler_linear();
|
|
|
|
|
2019-01-07 21:10:31 +00:00
|
|
|
Ok(Self {
|
2019-01-11 17:30:13 +00:00
|
|
|
device,
|
|
|
|
encoder: factory.create_command_buffer().into(),
|
2019-01-07 21:10:31 +00:00
|
|
|
factory,
|
2019-01-11 20:14:37 +00:00
|
|
|
|
2019-05-06 08:22:47 +00:00
|
|
|
win_color_view,
|
|
|
|
win_depth_view,
|
|
|
|
|
2019-01-11 17:30:13 +00:00
|
|
|
tgt_color_view,
|
|
|
|
tgt_depth_view,
|
2019-01-11 20:14:37 +00:00
|
|
|
|
2019-05-06 08:22:47 +00:00
|
|
|
tgt_color_res,
|
|
|
|
sampler,
|
|
|
|
|
2019-01-11 20:14:37 +00:00
|
|
|
skybox_pipeline,
|
2019-01-13 20:53:55 +00:00
|
|
|
figure_pipeline,
|
2019-01-14 23:13:58 +00:00
|
|
|
terrain_pipeline,
|
2019-08-14 21:28:37 +00:00
|
|
|
fluid_pipeline,
|
2019-01-30 12:11:34 +00:00
|
|
|
ui_pipeline,
|
2019-05-06 08:22:47 +00:00
|
|
|
postprocess_pipeline,
|
2019-08-03 05:42:33 +00:00
|
|
|
|
|
|
|
shader_reload_indicator,
|
2019-01-07 21:10:31 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
/// Get references to the internal render target views that get rendered to before post-processing.
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn tgt_views(&self) -> (&TgtColorView, &TgtDepthView) {
|
|
|
|
(&self.tgt_color_view, &self.tgt_depth_view)
|
|
|
|
}
|
|
|
|
|
2019-01-23 22:39:31 +00:00
|
|
|
/// Get references to the internal render target views that get displayed directly by the window.
|
2019-05-06 16:27:21 +00:00
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn win_views(&self) -> (&WinColorView, &WinDepthView) {
|
2019-05-06 08:22:47 +00:00
|
|
|
(&self.win_color_view, &self.win_depth_view)
|
2019-01-23 22:39:31 +00:00
|
|
|
}
|
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
/// Get mutable references to the internal render target views that get rendered to before post-processing.
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn tgt_views_mut(&mut self) -> (&mut TgtColorView, &mut TgtDepthView) {
|
|
|
|
(&mut self.tgt_color_view, &mut self.tgt_depth_view)
|
|
|
|
}
|
|
|
|
|
2019-01-23 22:39:31 +00:00
|
|
|
/// Get mutable references to the internal render target views that get displayed directly by the window.
|
2019-05-06 16:27:21 +00:00
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn win_views_mut(&mut self) -> (&mut WinColorView, &mut WinDepthView) {
|
2019-05-06 08:22:47 +00:00
|
|
|
(&mut self.win_color_view, &mut self.win_depth_view)
|
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Resize internal render targets to match window render target dimensions.
|
2019-05-06 08:22:47 +00:00
|
|
|
pub fn on_resize(&mut self) -> Result<(), RenderError> {
|
|
|
|
let dims = self.win_color_view.get_dimensions();
|
2019-05-06 12:03:15 +00:00
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
// Avoid panics when creating texture with w,h of 0,0.
|
2019-05-17 05:13:14 +00:00
|
|
|
if dims.0 != 0 && dims.1 != 0 {
|
|
|
|
let (tgt_color_view, tgt_depth_view, tgt_color_res) =
|
|
|
|
Self::create_rt_views(&mut self.factory, (dims.0, dims.1))?;
|
|
|
|
self.tgt_color_res = tgt_color_res;
|
|
|
|
self.tgt_color_view = tgt_color_view;
|
|
|
|
self.tgt_depth_view = tgt_depth_view;
|
|
|
|
}
|
2019-05-06 08:22:47 +00:00
|
|
|
|
|
|
|
Ok(())
|
2019-01-23 22:39:31 +00:00
|
|
|
}
|
|
|
|
|
2019-05-06 12:03:15 +00:00
|
|
|
fn create_rt_views(
|
|
|
|
factory: &mut gfx_device_gl::Factory,
|
|
|
|
size: (u16, u16),
|
|
|
|
) -> Result<(TgtColorView, TgtDepthView, TgtColorRes), RenderError> {
|
|
|
|
let (_, tgt_color_res, tgt_color_view) = factory
|
|
|
|
.create_render_target::<TgtColorFmt>(size.0, size.1)
|
|
|
|
.map_err(RenderError::CombinedError)?;;
|
|
|
|
let tgt_depth_view = factory
|
|
|
|
.create_depth_stencil_view_only::<TgtDepthFmt>(size.0, size.1)
|
|
|
|
.map_err(RenderError::CombinedError)?;;
|
|
|
|
Ok((tgt_color_view, tgt_depth_view, tgt_color_res))
|
|
|
|
}
|
|
|
|
|
2019-01-30 12:11:34 +00:00
|
|
|
/// Get the resolution of the render target.
|
|
|
|
pub fn get_resolution(&self) -> Vec2<u16> {
|
|
|
|
Vec2::new(
|
2019-05-07 11:27:40 +00:00
|
|
|
self.win_color_view.get_dimensions().0,
|
|
|
|
self.win_color_view.get_dimensions().1,
|
2019-01-30 12:11:34 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Queue the clearing of the color and depth targets ready for a new frame to be rendered.
|
2019-07-04 12:02:26 +00:00
|
|
|
pub fn clear(&mut self) {
|
2019-01-11 17:30:13 +00:00
|
|
|
self.encoder.clear_depth(&self.tgt_depth_view, 1.0);
|
2019-05-06 08:22:47 +00:00
|
|
|
self.encoder.clear_depth(&self.win_depth_view, 1.0);
|
2019-01-07 21:10:31 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Perform all queued draw calls for this frame and clean up discarded items.
|
2019-01-07 21:10:31 +00:00
|
|
|
pub fn flush(&mut self) {
|
2019-01-11 17:30:13 +00:00
|
|
|
self.encoder.flush(&mut self.device);
|
|
|
|
self.device.cleanup();
|
2019-08-03 05:42:33 +00:00
|
|
|
|
|
|
|
// If the shaders files were changed attempt to recreate the shaders
|
|
|
|
if self.shader_reload_indicator.reloaded() {
|
|
|
|
match create_pipelines(&mut self.factory, &mut self.shader_reload_indicator) {
|
|
|
|
Ok((
|
|
|
|
skybox_pipeline,
|
|
|
|
figure_pipeline,
|
2019-08-14 21:28:37 +00:00
|
|
|
terrain_pipeline,
|
|
|
|
fluid_pipeline,
|
2019-08-03 05:42:33 +00:00
|
|
|
ui_pipeline,
|
|
|
|
postprocess_pipeline,
|
|
|
|
)) => {
|
|
|
|
self.skybox_pipeline = skybox_pipeline;
|
|
|
|
self.figure_pipeline = figure_pipeline;
|
2019-08-14 21:28:37 +00:00
|
|
|
self.terrain_pipeline = terrain_pipeline;
|
|
|
|
self.fluid_pipeline = fluid_pipeline;
|
2019-08-03 05:42:33 +00:00
|
|
|
self.ui_pipeline = ui_pipeline;
|
|
|
|
self.postprocess_pipeline = postprocess_pipeline;
|
|
|
|
}
|
|
|
|
Err(e) => error!(
|
|
|
|
"Could not recreate shaders from assets due to an error: {:#?}",
|
|
|
|
e
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 21:10:31 +00:00
|
|
|
}
|
2019-01-11 20:14:37 +00:00
|
|
|
|
2019-01-13 20:53:55 +00:00
|
|
|
/// Create a new set of constants with the provided values.
|
|
|
|
pub fn create_consts<T: Copy + gfx::traits::Pod>(
|
2019-01-12 01:14:58 +00:00
|
|
|
&mut self,
|
2019-01-13 20:53:55 +00:00
|
|
|
vals: &[T],
|
2019-01-12 01:14:58 +00:00
|
|
|
) -> Result<Consts<T>, RenderError> {
|
2019-01-13 20:53:55 +00:00
|
|
|
let mut consts = Consts::new(&mut self.factory, vals.len());
|
|
|
|
consts.update(&mut self.encoder, vals)?;
|
2019-01-11 23:18:34 +00:00
|
|
|
Ok(consts)
|
2019-01-11 20:14:37 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 20:53:55 +00:00
|
|
|
/// Update a set of constants with the provided values.
|
2019-01-12 01:14:58 +00:00
|
|
|
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
|
|
|
&mut self,
|
|
|
|
consts: &mut Consts<T>,
|
2019-04-29 20:37:19 +00:00
|
|
|
vals: &[T],
|
2019-01-12 01:14:58 +00:00
|
|
|
) -> Result<(), RenderError> {
|
2019-01-13 20:53:55 +00:00
|
|
|
consts.update(&mut self.encoder, vals)
|
2019-01-12 01:14:58 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Create a new model from the provided mesh.
|
|
|
|
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
2019-04-29 20:37:19 +00:00
|
|
|
Ok(Model::new(&mut self.factory, mesh))
|
2019-01-11 20:14:37 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Create a new dynamic model with the specified size.
|
2019-05-04 14:28:21 +00:00
|
|
|
pub fn create_dynamic_model<P: Pipeline>(
|
|
|
|
&mut self,
|
|
|
|
size: usize,
|
|
|
|
) -> Result<DynamicModel<P>, RenderError> {
|
|
|
|
DynamicModel::new(&mut self.factory, size)
|
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Update a dynamic model with a mesh and a offset.
|
2019-05-04 14:28:21 +00:00
|
|
|
pub fn update_model<P: Pipeline>(
|
|
|
|
&mut self,
|
|
|
|
model: &DynamicModel<P>,
|
|
|
|
mesh: &Mesh<P>,
|
|
|
|
offset: usize,
|
|
|
|
) -> Result<(), RenderError> {
|
|
|
|
model.update(&mut self.encoder, mesh, offset)
|
|
|
|
}
|
|
|
|
|
2019-07-03 01:21:08 +00:00
|
|
|
/// Return the maximum supported texture size.
|
|
|
|
pub fn max_texture_size(&self) -> usize {
|
|
|
|
self.factory.get_capabilities().max_texture_size
|
|
|
|
}
|
|
|
|
|
2019-01-30 12:11:34 +00:00
|
|
|
/// Create a new texture from the provided image.
|
2019-04-29 20:37:19 +00:00
|
|
|
pub fn create_texture<P: Pipeline>(
|
|
|
|
&mut self,
|
|
|
|
image: &image::DynamicImage,
|
|
|
|
) -> Result<Texture<P>, RenderError> {
|
|
|
|
Texture::new(&mut self.factory, image)
|
2019-01-30 12:11:34 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions.
|
2019-02-23 02:41:52 +00:00
|
|
|
pub fn create_dynamic_texture<P: Pipeline>(
|
|
|
|
&mut self,
|
2019-04-29 20:37:19 +00:00
|
|
|
dims: Vec2<u16>,
|
2019-02-23 02:41:52 +00:00
|
|
|
) -> Result<Texture<P>, RenderError> {
|
2019-04-29 20:37:19 +00:00
|
|
|
Texture::new_dynamic(&mut self.factory, dims.x, dims.y)
|
2019-02-23 02:41:52 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Update a texture with the provided offset, size, and data.
|
2019-02-23 02:41:52 +00:00
|
|
|
pub fn update_texture<P: Pipeline>(
|
|
|
|
&mut self,
|
|
|
|
texture: &Texture<P>,
|
|
|
|
offset: [u16; 2],
|
|
|
|
size: [u16; 2],
|
2019-04-29 20:37:19 +00:00
|
|
|
data: &[[u8; 4]],
|
2019-02-23 02:41:52 +00:00
|
|
|
) -> Result<(), RenderError> {
|
2019-04-29 20:37:19 +00:00
|
|
|
texture.update(&mut self.encoder, offset, size, data)
|
2019-02-23 02:41:52 +00:00
|
|
|
}
|
|
|
|
|
2019-05-18 21:16:35 +00:00
|
|
|
/// Creates a download buffer, downloads the win_color_view, and converts to a image::DynamicImage.
|
|
|
|
pub fn create_screenshot(&mut self) -> Result<image::DynamicImage, RenderError> {
|
|
|
|
let (width, height) = self.get_resolution().into_tuple();
|
|
|
|
use gfx::{
|
|
|
|
format::{Formatted, SurfaceTyped},
|
|
|
|
memory::Typed,
|
|
|
|
};
|
|
|
|
type WinSurfaceData = <<WinColorFmt as Formatted>::Surface as SurfaceTyped>::DataType;
|
2019-05-19 16:25:02 +00:00
|
|
|
let download = self
|
2019-05-18 21:16:35 +00:00
|
|
|
.factory
|
|
|
|
.create_download_buffer::<WinSurfaceData>(width as usize * height as usize)
|
|
|
|
.map_err(|err| RenderError::BufferCreationError(err))?;
|
|
|
|
self.encoder
|
|
|
|
.copy_texture_to_buffer_raw(
|
|
|
|
self.win_color_view.raw().get_texture(),
|
|
|
|
None,
|
|
|
|
gfx::texture::RawImageInfo {
|
|
|
|
xoffset: 0,
|
|
|
|
yoffset: 0,
|
|
|
|
zoffset: 0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
depth: 0,
|
|
|
|
format: WinColorFmt::get_format(),
|
|
|
|
mipmap: 0,
|
|
|
|
},
|
|
|
|
download.raw(),
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.map_err(|err| RenderError::CopyError(err))?;
|
|
|
|
self.flush();
|
|
|
|
|
|
|
|
// Assumes that the format is Rgba8.
|
|
|
|
let raw_data = self
|
|
|
|
.factory
|
|
|
|
.read_mapping(&download)
|
|
|
|
.map_err(|err| RenderError::MappingError(err))?
|
2019-05-18 23:09:23 +00:00
|
|
|
.chunks_exact(width as usize)
|
2019-05-18 21:16:35 +00:00
|
|
|
.rev()
|
|
|
|
.flatten()
|
2019-05-18 23:09:23 +00:00
|
|
|
.flatten()
|
2019-05-18 21:16:35 +00:00
|
|
|
.map(|&e| e)
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
Ok(image::DynamicImage::ImageRgba8(
|
|
|
|
// Should not fail if the dimensions are correct.
|
|
|
|
image::ImageBuffer::from_raw(width as u32, height as u32, raw_data).unwrap(),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2019-01-12 13:56:34 +00:00
|
|
|
/// Queue the rendering of the provided skybox model in the upcoming frame.
|
2019-01-11 20:14:37 +00:00
|
|
|
pub fn render_skybox(
|
|
|
|
&mut self,
|
|
|
|
model: &Model<skybox::SkyboxPipeline>,
|
|
|
|
globals: &Consts<Globals>,
|
2019-01-13 20:53:55 +00:00
|
|
|
locals: &Consts<skybox::Locals>,
|
2019-01-11 20:14:37 +00:00
|
|
|
) {
|
|
|
|
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(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2019-01-13 20:53:55 +00:00
|
|
|
|
|
|
|
/// Queue the rendering of the provided figure model in the upcoming frame.
|
|
|
|
pub fn render_figure(
|
|
|
|
&mut self,
|
|
|
|
model: &Model<figure::FigurePipeline>,
|
|
|
|
globals: &Consts<Globals>,
|
|
|
|
locals: &Consts<figure::Locals>,
|
|
|
|
bones: &Consts<figure::BoneData>,
|
2019-07-21 15:04:36 +00:00
|
|
|
lights: &Consts<Light>,
|
2019-01-13 20:53:55 +00:00
|
|
|
) {
|
|
|
|
self.encoder.draw(
|
|
|
|
&model.slice,
|
|
|
|
&self.figure_pipeline.pso,
|
|
|
|
&figure::pipe::Data {
|
|
|
|
vbuf: model.vbuf.clone(),
|
|
|
|
locals: locals.buf.clone(),
|
|
|
|
globals: globals.buf.clone(),
|
|
|
|
bones: bones.buf.clone(),
|
2019-07-21 15:04:36 +00:00
|
|
|
lights: lights.buf.clone(),
|
2019-01-13 20:53:55 +00:00
|
|
|
tgt_color: self.tgt_color_view.clone(),
|
|
|
|
tgt_depth: self.tgt_depth_view.clone(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2019-01-14 23:13:58 +00:00
|
|
|
|
|
|
|
/// Queue the rendering of the provided terrain chunk model in the upcoming frame.
|
|
|
|
pub fn render_terrain_chunk(
|
|
|
|
&mut self,
|
|
|
|
model: &Model<terrain::TerrainPipeline>,
|
|
|
|
globals: &Consts<Globals>,
|
|
|
|
locals: &Consts<terrain::Locals>,
|
2019-07-21 15:04:36 +00:00
|
|
|
lights: &Consts<Light>,
|
2019-01-14 23:13:58 +00:00
|
|
|
) {
|
|
|
|
self.encoder.draw(
|
|
|
|
&model.slice,
|
|
|
|
&self.terrain_pipeline.pso,
|
|
|
|
&terrain::pipe::Data {
|
|
|
|
vbuf: model.vbuf.clone(),
|
|
|
|
locals: locals.buf.clone(),
|
|
|
|
globals: globals.buf.clone(),
|
2019-07-21 15:04:36 +00:00
|
|
|
lights: lights.buf.clone(),
|
2019-01-14 23:13:58 +00:00
|
|
|
tgt_color: self.tgt_color_view.clone(),
|
|
|
|
tgt_depth: self.tgt_depth_view.clone(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2019-01-30 12:11:34 +00:00
|
|
|
|
2019-08-14 21:28:37 +00:00
|
|
|
/// Queue the rendering of the provided terrain chunk model in the upcoming frame.
|
|
|
|
pub fn render_fluid_chunk(
|
|
|
|
&mut self,
|
|
|
|
model: &Model<fluid::FluidPipeline>,
|
|
|
|
globals: &Consts<Globals>,
|
|
|
|
locals: &Consts<terrain::Locals>,
|
|
|
|
lights: &Consts<Light>,
|
|
|
|
) {
|
|
|
|
self.encoder.draw(
|
|
|
|
&model.slice,
|
|
|
|
&self.fluid_pipeline.pso,
|
|
|
|
&fluid::pipe::Data {
|
|
|
|
vbuf: model.vbuf.clone(),
|
|
|
|
locals: locals.buf.clone(),
|
|
|
|
globals: globals.buf.clone(),
|
|
|
|
lights: lights.buf.clone(),
|
|
|
|
tgt_color: self.tgt_color_view.clone(),
|
|
|
|
tgt_depth: self.tgt_depth_view.clone(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-30 12:11:34 +00:00
|
|
|
/// Queue the rendering of the provided UI element in the upcoming frame.
|
|
|
|
pub fn render_ui_element(
|
|
|
|
&mut self,
|
|
|
|
model: &Model<ui::UiPipeline>,
|
|
|
|
tex: &Texture<ui::UiPipeline>,
|
2019-03-20 05:13:42 +00:00
|
|
|
scissor: Aabr<u16>,
|
2019-05-14 06:43:07 +00:00
|
|
|
globals: &Consts<Globals>,
|
|
|
|
locals: &Consts<ui::Locals>,
|
2019-01-30 12:11:34 +00:00
|
|
|
) {
|
2019-03-20 05:13:42 +00:00
|
|
|
let Aabr { min, max } = scissor;
|
2019-01-30 12:11:34 +00:00
|
|
|
self.encoder.draw(
|
|
|
|
&model.slice,
|
|
|
|
&self.ui_pipeline.pso,
|
|
|
|
&ui::pipe::Data {
|
|
|
|
vbuf: model.vbuf.clone(),
|
2019-04-29 20:37:19 +00:00
|
|
|
scissor: gfx::Rect {
|
|
|
|
x: min.x,
|
|
|
|
y: min.y,
|
|
|
|
w: max.x - min.x,
|
|
|
|
h: max.y - min.y,
|
|
|
|
},
|
2019-01-30 12:11:34 +00:00
|
|
|
tex: (tex.srv.clone(), tex.sampler.clone()),
|
2019-05-14 06:43:07 +00:00
|
|
|
locals: locals.buf.clone(),
|
|
|
|
globals: globals.buf.clone(),
|
2019-05-06 08:22:47 +00:00
|
|
|
tgt_color: self.win_color_view.clone(),
|
|
|
|
tgt_depth: self.win_depth_view.clone(),
|
2019-01-30 12:11:34 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2019-05-06 08:22:47 +00:00
|
|
|
|
|
|
|
pub fn render_post_process(
|
|
|
|
&mut self,
|
|
|
|
model: &Model<postprocess::PostProcessPipeline>,
|
|
|
|
globals: &Consts<Globals>,
|
|
|
|
locals: &Consts<postprocess::Locals>,
|
|
|
|
) {
|
|
|
|
self.encoder.draw(
|
|
|
|
&model.slice,
|
|
|
|
&self.postprocess_pipeline.pso,
|
|
|
|
&postprocess::pipe::Data {
|
|
|
|
vbuf: model.vbuf.clone(),
|
|
|
|
locals: locals.buf.clone(),
|
|
|
|
globals: globals.buf.clone(),
|
|
|
|
src_sampler: (self.tgt_color_res.clone(), self.sampler.clone()),
|
|
|
|
tgt_color: self.win_color_view.clone(),
|
|
|
|
tgt_depth: self.win_depth_view.clone(),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2019-01-11 20:14:37 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
struct GfxPipeline<P: gfx::pso::PipelineInit> {
|
2019-01-11 20:14:37 +00:00
|
|
|
pso: gfx::pso::PipelineState<gfx_backend::Resources, P::Meta>,
|
2019-01-07 21:10:31 +00:00
|
|
|
}
|
2019-01-11 23:18:34 +00:00
|
|
|
|
2019-08-15 20:38:13 +00:00
|
|
|
/// Creates all the pipelines used to render.
|
2019-08-03 05:42:33 +00:00
|
|
|
fn create_pipelines(
|
|
|
|
factory: &mut gfx_backend::Factory,
|
|
|
|
shader_reload_indicator: &mut ReloadIndicator,
|
|
|
|
) -> Result<
|
|
|
|
(
|
|
|
|
GfxPipeline<skybox::pipe::Init<'static>>,
|
|
|
|
GfxPipeline<figure::pipe::Init<'static>>,
|
|
|
|
GfxPipeline<terrain::pipe::Init<'static>>,
|
2019-08-14 21:28:37 +00:00
|
|
|
GfxPipeline<fluid::pipe::Init<'static>>,
|
2019-08-03 05:42:33 +00:00
|
|
|
GfxPipeline<ui::pipe::Init<'static>>,
|
|
|
|
GfxPipeline<postprocess::pipe::Init<'static>>,
|
|
|
|
),
|
|
|
|
RenderError,
|
|
|
|
> {
|
|
|
|
let globals =
|
|
|
|
assets::load_watched::<String>("voxygen.shaders.include.globals", shader_reload_indicator)
|
|
|
|
.unwrap();
|
|
|
|
let sky =
|
|
|
|
assets::load_watched::<String>("voxygen.shaders.include.sky", shader_reload_indicator)
|
|
|
|
.unwrap();
|
|
|
|
let light =
|
|
|
|
assets::load_watched::<String>("voxygen.shaders.include.light", shader_reload_indicator)
|
|
|
|
.unwrap();
|
2019-08-04 19:54:08 +00:00
|
|
|
let srgb =
|
|
|
|
assets::load_watched::<String>("voxygen.shaders.include.srgb", shader_reload_indicator)
|
|
|
|
.unwrap();
|
2019-08-15 01:35:56 +00:00
|
|
|
let random =
|
|
|
|
assets::load_watched::<String>("voxygen.shaders.include.random", shader_reload_indicator)
|
|
|
|
.unwrap();
|
2019-08-03 05:42:33 +00:00
|
|
|
|
|
|
|
let mut include_ctx = IncludeContext::new();
|
|
|
|
include_ctx.include("globals.glsl", &globals);
|
|
|
|
include_ctx.include("sky.glsl", &sky);
|
|
|
|
include_ctx.include("light.glsl", &light);
|
2019-08-04 19:54:08 +00:00
|
|
|
include_ctx.include("srgb.glsl", &srgb);
|
2019-08-15 01:35:56 +00:00
|
|
|
include_ctx.include("random.glsl", &random);
|
2019-08-03 05:42:33 +00:00
|
|
|
|
|
|
|
// Construct a pipeline for rendering skyboxes
|
|
|
|
let skybox_pipeline = create_pipeline(
|
|
|
|
factory,
|
|
|
|
skybox::pipe::new(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.skybox-vert", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.skybox-frag", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
|
|
|
&include_ctx,
|
2019-08-15 01:35:56 +00:00
|
|
|
gfx::state::CullFace::Back,
|
2019-08-03 05:42:33 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
// Construct a pipeline for rendering figures
|
|
|
|
let figure_pipeline = create_pipeline(
|
|
|
|
factory,
|
|
|
|
figure::pipe::new(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.figure-vert", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.figure-frag", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
|
|
|
&include_ctx,
|
2019-08-15 01:35:56 +00:00
|
|
|
gfx::state::CullFace::Back,
|
2019-08-03 05:42:33 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
// Construct a pipeline for rendering terrain
|
|
|
|
let terrain_pipeline = create_pipeline(
|
|
|
|
factory,
|
|
|
|
terrain::pipe::new(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.terrain-vert", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.terrain-frag", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
|
|
|
&include_ctx,
|
2019-08-15 01:35:56 +00:00
|
|
|
gfx::state::CullFace::Back,
|
2019-08-03 05:42:33 +00:00
|
|
|
)?;
|
|
|
|
|
2019-08-14 21:28:37 +00:00
|
|
|
// Construct a pipeline for rendering fluids
|
|
|
|
let fluid_pipeline = create_pipeline(
|
|
|
|
factory,
|
|
|
|
fluid::pipe::new(),
|
|
|
|
&assets::load_watched::<String>("voxygen.shaders.fluid-vert", shader_reload_indicator)
|
|
|
|
.unwrap(),
|
|
|
|
&assets::load_watched::<String>("voxygen.shaders.fluid-frag", shader_reload_indicator)
|
|
|
|
.unwrap(),
|
|
|
|
&include_ctx,
|
2019-08-15 01:35:56 +00:00
|
|
|
gfx::state::CullFace::Nothing,
|
2019-08-14 21:28:37 +00:00
|
|
|
)?;
|
|
|
|
|
2019-08-03 05:42:33 +00:00
|
|
|
// Construct a pipeline for rendering UI elements
|
|
|
|
let ui_pipeline = create_pipeline(
|
|
|
|
factory,
|
|
|
|
ui::pipe::new(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.ui-vert", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
2019-08-15 20:38:13 +00:00
|
|
|
&assets::load_watched::<String>("voxygen.shaders.ui-frag", shader_reload_indicator)
|
2019-08-03 05:42:33 +00:00
|
|
|
.unwrap(),
|
|
|
|
&include_ctx,
|
2019-08-15 01:35:56 +00:00
|
|
|
gfx::state::CullFace::Back,
|
2019-08-03 05:42:33 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
// Construct a pipeline for rendering our post-processing
|
|
|
|
let postprocess_pipeline = create_pipeline(
|
|
|
|
factory,
|
|
|
|
postprocess::pipe::new(),
|
|
|
|
&assets::load_watched::<String>(
|
2019-08-15 20:38:13 +00:00
|
|
|
"voxygen.shaders.postprocess-vert",
|
2019-08-03 05:42:33 +00:00
|
|
|
shader_reload_indicator,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
&assets::load_watched::<String>(
|
2019-08-15 20:38:13 +00:00
|
|
|
"voxygen.shaders.postprocess-frag",
|
2019-08-03 05:42:33 +00:00
|
|
|
shader_reload_indicator,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
&include_ctx,
|
2019-08-15 01:35:56 +00:00
|
|
|
gfx::state::CullFace::Back,
|
2019-08-03 05:42:33 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok((
|
|
|
|
skybox_pipeline,
|
|
|
|
figure_pipeline,
|
|
|
|
terrain_pipeline,
|
2019-08-14 21:28:37 +00:00
|
|
|
fluid_pipeline,
|
2019-08-03 05:42:33 +00:00
|
|
|
ui_pipeline,
|
|
|
|
postprocess_pipeline,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2019-01-12 13:56:34 +00:00
|
|
|
/// Create a new pipeline from the provided vertex shader and fragment shader.
|
2019-01-11 23:18:34 +00:00
|
|
|
fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
|
|
|
factory: &mut gfx_backend::Factory,
|
|
|
|
pipe: P,
|
2019-05-12 09:10:13 +00:00
|
|
|
vs: &str,
|
|
|
|
fs: &str,
|
|
|
|
ctx: &IncludeContext,
|
2019-08-15 01:35:56 +00:00
|
|
|
cull_face: gfx::state::CullFace,
|
2019-01-11 23:18:34 +00:00
|
|
|
) -> Result<GfxPipeline<P>, RenderError> {
|
2019-05-12 09:10:13 +00:00
|
|
|
let vs = ctx.expand(vs).map_err(RenderError::IncludeError)?;
|
|
|
|
let fs = ctx.expand(fs).map_err(RenderError::IncludeError)?;
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
let program = factory
|
2019-05-12 09:10:13 +00:00
|
|
|
.link_program(vs.as_bytes(), fs.as_bytes())
|
2019-01-11 23:18:34 +00:00
|
|
|
.map_err(|err| RenderError::PipelineError(gfx::PipelineStateError::Program(err)))?;
|
|
|
|
|
|
|
|
Ok(GfxPipeline {
|
2019-04-29 20:37:19 +00:00
|
|
|
pso: factory
|
|
|
|
.create_pipeline_from_program(
|
2019-01-11 23:18:34 +00:00
|
|
|
&program,
|
|
|
|
gfx::Primitive::TriangleList,
|
|
|
|
gfx::state::Rasterizer {
|
|
|
|
front_face: gfx::state::FrontFace::CounterClockwise,
|
2019-08-15 01:35:56 +00:00
|
|
|
cull_face,
|
2019-01-11 23:18:34 +00:00
|
|
|
method: gfx::state::RasterMethod::Fill,
|
|
|
|
offset: None,
|
|
|
|
samples: Some(gfx::state::MultiSample),
|
|
|
|
},
|
|
|
|
pipe,
|
|
|
|
)
|
2019-05-17 09:22:32 +00:00
|
|
|
// Do some funky things to work around an oddity in gfx's error ownership rules.
|
2019-04-29 20:37:19 +00:00
|
|
|
.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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})?,
|
2019-01-11 23:18:34 +00:00
|
|
|
})
|
|
|
|
}
|