Render Ui

This commit is contained in:
Imbris 2020-12-04 00:38:26 -05:00 committed by Avi Weinstock
parent 9f399f9076
commit 617ae80d02
35 changed files with 926 additions and 337 deletions

View File

@ -11,9 +11,9 @@ uniform u_locals {
vec4 w_pos;
};
layout(set = 1, binding = 1)
layout(set = 2, binding = 0)
uniform texture2D t_tex;
layout(set = 1, binding = 2)
layout(set = 2, binding = 1)
uniform sampler s_tex;
layout(location = 0) out vec4 tgt_color;

View File

@ -13,9 +13,9 @@ uniform u_locals {
vec4 w_pos;
};
layout(set = 1, binding = 1)
layout(set = 2, binding = 0)
uniform texture2D t_tex;
layout(set = 1, binding = 2)
layout(set = 2, binding = 1)
uniform sampler s_tex;
layout(location = 0) out vec2 f_uv;
@ -33,10 +33,10 @@ void main() {
f_uv = v_uv;
// Fixed scale In-game element
vec4 projected_pos = /*proj_mat * view_mat*/all_mat * vec4(w_pos.xyz - focus_off.xyz, 1.0);
gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos/* * projected_pos.w*/, -1.0, /*projected_pos.w*/1.0);
gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos/* * projected_pos.w*/, 0.0, /*projected_pos.w*/1.0);
} else if (v_mode == uint(3)) {
// HACK: North facing source rectangle.
gl_Position = vec4(v_pos, -1.0, 1.0);
gl_Position = vec4(v_pos, 0.0, 1.0);
vec2 look_at_dir = normalize(vec2(-view_mat[0][2], -view_mat[1][2]));
// TODO: Consider cleaning up matrix to something more efficient (e.g. a mat3).
vec2 aspect_ratio = textureSize(sampler2D(t_tex, s_tex), 0).yx;
@ -53,11 +53,11 @@ void main() {
mat2 look_at = mat2(look_at_dir.y, -look_at_dir.x, look_at_dir.x, look_at_dir.y);
vec2 v_centered = (v_pos - v_center) / aspect_ratio;
vec2 v_rotated = look_at * v_centered;
gl_Position = vec4(aspect_ratio * v_rotated + v_center, -1.0, 1.0);
gl_Position = vec4(aspect_ratio * v_rotated + v_center, 0.0, 1.0);
} else {
// Interface element
f_uv = v_uv;
gl_Position = vec4(v_pos, -1.0, 1.0);
gl_Position = vec4(v_pos, 0.0, 1.0);
}
f_mode = v_mode;
}

View File

@ -1584,7 +1584,8 @@ impl CharSelectionUi {
}
// TODO: do we need globals?
pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer); }
pub fn render(&self, renderer: &mut Renderer) { /* self.ui.render(renderer);*/
}
}
#[derive(Default)]

View File

@ -1,4 +1,5 @@
mod client_init;
mod scene;
mod ui;
use super::char_selection::CharSelectionState;
@ -20,6 +21,7 @@ use client::{
use client_init::{ClientConnArgs, ClientInit, Error as InitError, Msg as InitMsg};
use common::comp;
use common_base::span;
use scene::Scene;
use std::{fmt::Debug, sync::Arc};
use tokio::runtime;
use tracing::error;
@ -29,6 +31,7 @@ pub struct MainMenuState {
main_menu_ui: MainMenuUi,
// Used for client creation.
client_init: Option<ClientInit>,
scene: Scene,
}
impl MainMenuState {
@ -37,6 +40,7 @@ impl MainMenuState {
Self {
main_menu_ui: MainMenuUi::new(global_state),
client_init: None,
scene: Scene::new(global_state.window.renderer_mut()),
}
}
}
@ -342,8 +346,18 @@ impl PlayState for MainMenuState {
fn name(&self) -> &'static str { "Title" }
fn render(&mut self, renderer: &mut Renderer, _: &Settings) {
// TODO: maybe the drawer should be passed in from above?
let mut drawer = match renderer
.start_recording_frame(self.scene.global_bind_group())
.unwrap()
{
Some(d) => d,
// Couldn't get swap chain texture this fime
None => return,
};
// Draw the UI to the screen.
self.main_menu_ui.render(renderer);
self.main_menu_ui.render(&mut drawer.third_pass().draw_ui());
}
}

View File

@ -0,0 +1,28 @@
use crate::render::{
GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Renderer, Shadow, ShadowLocals,
};
pub struct Scene {
// global_data: GlobalModel,
// lod_data: LodData,
bind_group: GlobalsBindGroup,
}
impl Scene {
pub fn new(renderer: &mut Renderer) -> Self {
let global_data = GlobalModel {
globals: renderer.create_consts(&[Globals::default()]),
lights: renderer.create_consts(&[Light::default(); 32]),
shadows: renderer.create_consts(&[Shadow::default(); 32]),
shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]),
};
let lod_data = LodData::dummy(renderer);
let bind_group = renderer.bind_globals(&global_data, &lod_data);
Self { bind_group }
}
pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.bind_group }
}

View File

@ -6,7 +6,7 @@ mod servers;
use crate::{
i18n::{LanguageMetadata, LocalizationHandle},
render::Renderer,
render::UiDrawer,
ui::{
self,
fonts::IcedFonts as Fonts,
@ -477,7 +477,7 @@ pub struct MainMenuUi {
controls: Controls,
}
impl<'a> MainMenuUi {
impl MainMenuUi {
pub fn new(global_state: &mut GlobalState) -> Self {
// Load language
let i18n = &global_state.i18n.read();
@ -582,5 +582,5 @@ impl<'a> MainMenuUi {
events
}
pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer); }
pub fn render<'a>(&'a self, drawer: &mut UiDrawer<'_, 'a>) { self.ui.render(drawer); }
}

View File

@ -2,7 +2,7 @@ use bytemuck::Pod;
use wgpu::util::DeviceExt;
pub struct Buffer<T: Copy + Pod> {
pub buf: wgpu::Buffer,
pub(super) buf: wgpu::Buffer,
// Size in number of elements
// TODO: determine if this is a good name
len: usize,

View File

@ -37,11 +37,12 @@ pub use self::{
ui::{
create_quad as create_ui_quad,
create_quad_vert_gradient as create_ui_quad_vert_gradient, create_tri as create_ui_tri,
Locals as UiLocals, Mode as UiMode, Vertex as UiVertex,
Locals as UiLocals, LocalsBindGroup as UiLocalsBindGroup, Mode as UiMode,
TextureBindGroup as UiTextureBindGroup, Vertex as UiVertex,
},
GlobalModel, Globals, GlobalsLayouts, Light, Shadow,
GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light, Shadow,
},
renderer::{ColLightInfo, Renderer},
renderer::{ColLightInfo, Drawer, Renderer, UiDrawer},
texture::Texture,
};
pub use wgpu::{AddressMode, FilterMode};

View File

@ -13,7 +13,7 @@ pub struct SubModel<'a, V: Vertex> {
}
impl<'a, V: Vertex> SubModel<'a, V> {
pub fn buf(&self) -> &wgpu::Buffer { self.buf }
pub(super) fn buf(&self) -> &wgpu::Buffer { self.buf }
}
/// Represents a mesh that has been sent to the GPU.
@ -38,7 +38,7 @@ impl<V: Vertex> Model<V> {
}
}
pub fn buf(&self) -> &wgpu::Buffer { &self.vbuf.buf }
pub(super) fn buf(&self) -> &wgpu::Buffer { &self.vbuf.buf }
pub fn len(&self) -> usize { self.vbuf.len() }
}

View File

@ -150,7 +150,6 @@ impl CloudsPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -143,7 +143,6 @@ impl FigureLayout {
},
count: None,
},
// TODO: does this change at the same frequency?
// col lights
wgpu::BindGroupLayoutEntry {
binding: 2,
@ -192,7 +191,6 @@ impl FigurePipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -105,7 +105,6 @@ impl FluidPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -35,6 +35,25 @@ pub struct LodData {
}
impl LodData {
pub fn dummy(renderer: &mut Renderer) -> Self {
let map_size = Vec2::new(1, 1);
let map_border = [0.0, 0.0, 0.0, 0.0];
let map_image = [0];
let alt_image = [0];
let horizon_image = [0x_00_01_00_01];
//let map_border = [0.0, 0.0, 0.0, 0.0];
Self::new(
renderer,
map_size,
&map_image,
&alt_image,
&horizon_image,
1,
//map_border.into(),
)
}
pub fn new(
renderer: &mut Renderer,
map_size: Vec2<u32>,
@ -44,65 +63,54 @@ impl LodData {
tgt_detail: u32,
//border_color: gfx::texture::PackedColor,
) -> Self {
let mut texture_info = wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width: map_size.x,
height: map_size.y,
depth: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
};
let mut create_texture = |format, data| {
let texture_info = wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width: map_size.x,
height: map_size.y,
depth: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
};
let sampler_info = wgpu::SamplerDescriptor {
label: None,
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
..Default::default()
};
let sampler_info = wgpu::SamplerDescriptor {
label: None,
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
..Default::default()
};
let mut view_info = wgpu::TextureViewDescriptor {
label: None,
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
dimension: Some(wgpu::TextureViewDimension::D2),
aspect: wgpu::TextureAspect::All,
base_mip_level: 0,
level_count: None,
base_array_layer: 0,
array_layer_count: None,
};
let view_info = wgpu::TextureViewDescriptor {
label: None,
format: Some(format),
dimension: Some(wgpu::TextureViewDimension::D2),
aspect: wgpu::TextureAspect::All,
base_mip_level: 0,
level_count: None,
base_array_layer: 0,
array_layer_count: None,
};
let map = renderer.create_texture_with_data_raw(
&texture_info,
&view_info,
&sampler_info,
bytemuck::cast_slice(lod_base),
);
texture_info.format = wgpu::TextureFormat::Rg16Uint;
view_info.format = Some(wgpu::TextureFormat::Rg16Uint);
let alt = renderer.create_texture_with_data_raw(
&texture_info,
&view_info,
&sampler_info,
bytemuck::cast_slice(lod_base),
);
texture_info.format = wgpu::TextureFormat::Rgba8Unorm;
view_info.format = Some(wgpu::TextureFormat::Rg16Uint);
let horizon = renderer.create_texture_with_data_raw(
&texture_info,
&view_info,
&sampler_info,
bytemuck::cast_slice(lod_base),
);
renderer.create_texture_with_data_raw(
&texture_info,
&view_info,
&sampler_info,
bytemuck::cast_slice(data),
)
};
let map = create_texture(wgpu::TextureFormat::Rgba8UnormSrgb, lod_base);
let alt = create_texture(wgpu::TextureFormat::Rg16Uint, lod_alt);
let horizon = create_texture(wgpu::TextureFormat::Rgba8Unorm, lod_horizon);
Self {
map,
@ -173,7 +181,6 @@ impl LodTerrainPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -10,7 +10,7 @@ pub mod sprite;
pub mod terrain;
pub mod ui;
use super::Consts;
use super::{Consts, Texture};
use crate::scene::camera::CameraMode;
use bytemuck::{Pod, Zeroable};
use common::terrain::BlockKind;
@ -225,6 +225,10 @@ pub struct GlobalModel {
pub shadow_mats: Consts<shadow::Locals>,
}
pub struct GlobalsBindGroup {
pub(super) bind_group: wgpu::BindGroup,
}
pub struct GlobalsLayouts {
pub globals: wgpu::BindGroupLayout,
}
@ -315,7 +319,7 @@ impl GlobalsLayouts {
ty: wgpu::BindingType::Sampler { comparison: false },
count: None,
},
// light shadows
// light shadows (ie shadows from a light?)
wgpu::BindGroupLayoutEntry {
binding: 9,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
@ -382,4 +386,96 @@ impl GlobalsLayouts {
Self { globals }
}
pub fn bind(
&self,
device: &wgpu::Device,
global_model: &GlobalModel,
lod_data: &lod_terrain::LodData,
noise: &Texture,
point_shadow_map: &Texture,
directed_shadow_map: &Texture,
) -> GlobalsBindGroup {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &self.globals,
entries: &[
// Global uniform
wgpu::BindGroupEntry {
binding: 0,
resource: global_model.globals.buf().as_entire_binding(),
},
// Noise tex
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&noise.view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(&noise.sampler),
},
// Light uniform
wgpu::BindGroupEntry {
binding: 3,
resource: global_model.lights.buf().as_entire_binding(),
},
// Shadow uniform
wgpu::BindGroupEntry {
binding: 4,
resource: global_model.shadows.buf().as_entire_binding(),
},
// Alt texture
wgpu::BindGroupEntry {
binding: 5,
resource: wgpu::BindingResource::TextureView(&lod_data.alt.view),
},
wgpu::BindGroupEntry {
binding: 6,
resource: wgpu::BindingResource::Sampler(&lod_data.alt.sampler),
},
// Horizon texture
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::TextureView(&lod_data.horizon.view),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::Sampler(&lod_data.horizon.sampler),
},
// light shadows
wgpu::BindGroupEntry {
binding: 9,
resource: global_model.shadow_mats.buf().as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::TextureView(&point_shadow_map.view),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::Sampler(&point_shadow_map.sampler),
},
// directed shadow maps
wgpu::BindGroupEntry {
binding: 12,
resource: wgpu::BindingResource::TextureView(&directed_shadow_map.view),
},
wgpu::BindGroupEntry {
binding: 13,
resource: wgpu::BindingResource::Sampler(&directed_shadow_map.sampler),
},
// lod map (t_map)
wgpu::BindGroupEntry {
binding: 14,
resource: wgpu::BindingResource::TextureView(&lod_data.map.view),
},
wgpu::BindGroupEntry {
binding: 15,
resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler),
},
],
});
GlobalsBindGroup { bind_group }
}
}

View File

@ -189,7 +189,6 @@ impl ParticlePipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -146,7 +146,6 @@ impl PostProcessPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -22,7 +22,6 @@ impl Locals {
pub fn default() -> Self { Self::new(Mat4::identity(), Mat4::identity()) }
// TODO: unused?
fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
@ -131,7 +130,6 @@ impl ShadowFigurePipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,
@ -214,7 +212,6 @@ impl ShadowPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -46,7 +46,6 @@ impl SkyboxPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -176,7 +176,6 @@ impl SpriteLayout {
label: None,
entries: &[
// locals
// TODO: different freq
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
@ -239,7 +238,6 @@ impl SpritePipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -170,7 +170,6 @@ impl TerrainLayout {
count: None,
},
// col lights
// TODO: same frequency?
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
@ -218,7 +217,6 @@ impl TerrainPipeline {
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -1,4 +1,4 @@
use super::super::{AaMode, GlobalsLayouts, Quad, Tri};
use super::super::{AaMode, Consts, GlobalsLayouts, Quad, Texture, Tri};
use bytemuck::{Pod, Zeroable};
use vek::*;
@ -80,11 +80,20 @@ impl Mode {
}
}
pub struct UILayout {
pub locals: wgpu::BindGroupLayout,
pub struct LocalsBindGroup {
pub(in super::super) bind_group: wgpu::BindGroup,
}
impl UILayout {
pub struct TextureBindGroup {
pub(in super::super) bind_group: wgpu::BindGroup,
}
pub struct UiLayout {
pub locals: wgpu::BindGroupLayout,
pub texture: wgpu::BindGroupLayout,
}
impl UiLayout {
pub fn new(device: &wgpu::Device) -> Self {
Self {
locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -100,9 +109,14 @@ impl UILayout {
},
count: None,
},
],
}),
texture: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
entries: &[
// texture
wgpu::BindGroupLayoutEntry {
binding: 1,
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::SampledTexture {
component_type: wgpu::TextureComponentType::Float,
@ -112,7 +126,7 @@ impl UILayout {
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
binding: 1,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false },
count: None,
@ -121,33 +135,64 @@ impl UILayout {
}),
}
}
pub fn bind_locals(&self, device: &wgpu::Device, locals: &Consts<Locals>) -> LocalsBindGroup {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &self.locals,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: locals.buf().as_entire_binding(),
}],
});
LocalsBindGroup { bind_group }
}
pub fn bind_texture(&self, device: &wgpu::Device, texture: &Texture) -> TextureBindGroup {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &self.texture,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&texture.sampler),
},
],
});
TextureBindGroup { bind_group }
}
}
pub struct UIPipeline {
pub struct UiPipeline {
pub pipeline: wgpu::RenderPipeline,
}
impl UIPipeline {
impl UiPipeline {
pub fn new(
device: &wgpu::Device,
vs_module: &wgpu::ShaderModule,
fs_module: &wgpu::ShaderModule,
sc_desc: &wgpu::SwapChainDescriptor,
global_layout: &GlobalsLayouts,
layout: &UILayout,
layout: &UiLayout,
aa_mode: AaMode,
) -> Self {
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("UI pipeline layout"),
label: Some("Ui pipeline layout"),
push_constant_ranges: &[],
bind_group_layouts: &[&global_layout.globals, &layout.locals],
bind_group_layouts: &[&global_layout.globals, &layout.locals, &layout.texture],
});
let samples = match aa_mode {
AaMode::None | AaMode::Fxaa => 1,
// TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::SsaaX4 => 1,
AaMode::MsaaX4 => 4,
AaMode::MsaaX8 => 8,
AaMode::MsaaX16 => 16,

View File

@ -1,3 +1,8 @@
mod bind_group;
mod drawer;
pub use drawer::{Drawer, UiDrawer};
use super::{
consts::Consts,
instances::Instances,
@ -8,8 +13,8 @@ use super::{
ui, GlobalsLayouts,
},
texture::Texture,
AaMode, AddressMode, CloudMode, FilterMode, FluidMode, LightingMode, RenderError, RenderMode,
ShadowMapMode, ShadowMode, Vertex,
AaMode, AddressMode, CloudMode, FilterMode, FluidMode, GlobalsBindGroup, LightingMode,
RenderError, RenderMode, ShadowMapMode, ShadowMode, Vertex,
};
use common::assets::{self, AssetExt, AssetHandle};
use common_base::span;
@ -20,6 +25,7 @@ use vek::*;
/// A type representing data that can be converted to an immutable texture map
/// of ColLight data (used for texture atlases created during greedy meshing).
// TODO: revert to u16
pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u32>);
/// Load from a GLSL file.
@ -116,9 +122,9 @@ impl Shaders {
pub struct ShadowMapRenderer {
// directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
// point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
directed_depth_stencil: Texture,
directed_depth: Texture,
point_depth_stencil: Texture,
point_depth: Texture,
point_pipeline: shadow::ShadowPipeline,
terrain_directed_pipeline: shadow::ShadowPipeline,
@ -128,6 +134,7 @@ pub struct ShadowMapRenderer {
/// A type that stores all the layouts associated with this renderer.
pub struct Layouts {
// TODO: pub(self)??
pub(self) global: GlobalsLayouts,
pub(self) clouds: clouds::CloudsLayout,
@ -137,7 +144,7 @@ pub struct Layouts {
pub(self) shadow: shadow::ShadowLayout,
pub(self) sprite: sprite::SpriteLayout,
pub(self) terrain: terrain::TerrainLayout,
pub(self) ui: ui::UILayout,
pub(self) ui: ui::UiLayout,
}
/// A type that encapsulates rendering state. `Renderer` is central to Voxygen's
@ -156,7 +163,7 @@ pub struct Renderer {
win_depth_view: wgpu::TextureView,
tgt_color_view: wgpu::TextureView,
tgt_depth_stencil_view: wgpu::TextureView,
tgt_depth_view: wgpu::TextureView,
// TODO: rename
tgt_color_pp_view: wgpu::TextureView,
@ -177,7 +184,7 @@ pub struct Renderer {
skybox_pipeline: skybox::SkyboxPipeline,
sprite_pipeline: sprite::SpritePipeline,
terrain_pipeline: terrain::TerrainPipeline,
ui_pipeline: ui::UIPipeline,
ui_pipeline: ui::UiPipeline,
shaders: AssetHandle<Shaders>,
@ -273,7 +280,7 @@ impl Renderer {
let shadow = shadow::ShadowLayout::new(&device);
let sprite = sprite::SpriteLayout::new(&device);
let terrain = terrain::TerrainLayout::new(&device);
let ui = ui::UILayout::new(&device);
let ui = ui::UiLayout::new(&device);
Layouts {
global,
@ -313,7 +320,7 @@ impl Renderer {
shadow_views.is_some(),
)?;
let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) =
let (tgt_color_view, tgt_depth_view, tgt_color_pp_view, win_depth_view) =
Self::create_rt_views(&device, (dims.width, dims.height), &mode)?;
let shadow_map = if let (
@ -327,16 +334,16 @@ impl Renderer {
figure_directed_shadow_pipeline,
shadow_views,
) {
let (point_depth_stencil, directed_depth_stencil) = shadow_views;
let (point_depth, directed_depth) = shadow_views;
let layout = shadow::ShadowLayout::new(&device);
Some(ShadowMapRenderer {
directed_depth_stencil,
directed_depth,
// point_encoder: factory.create_command_buffer().into(),
// directed_encoder: factory.create_command_buffer().into(),
point_depth_stencil,
point_depth,
point_pipeline,
terrain_directed_pipeline,
@ -378,7 +385,7 @@ impl Renderer {
win_depth_view,
tgt_color_view,
tgt_depth_stencil_view,
tgt_depth_view,
tgt_color_pp_view,
sampler,
@ -411,7 +418,7 @@ impl Renderer {
/// before post-processing.
#[allow(dead_code)]
pub fn tgt_views(&self) -> (&wgpu::TextureView, &wgpu::TextureView) {
(&self.tgt_color_view, &self.tgt_depth_stencil_view)
(&self.tgt_color_view, &self.tgt_depth_view)
}
/// Get references to the internal render target views that get displayed
@ -446,19 +453,19 @@ impl Renderer {
self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc);
// Resize other render targets
let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) =
let (tgt_color_view, tgt_depth_view, tgt_color_pp_view, win_depth_view) =
Self::create_rt_views(&mut self.device, (dims.x, dims.y), &self.mode)?;
self.win_depth_view = win_depth_view;
self.tgt_color_view = tgt_color_view;
self.tgt_depth_stencil_view = tgt_depth_stencil_view;
self.tgt_depth_view = tgt_depth_view;
self.tgt_color_pp_view = tgt_color_pp_view;
if let (Some(shadow_map), ShadowMode::Map(mode)) =
(self.shadow_map.as_mut(), self.mode.shadow)
{
match Self::create_shadow_views(&mut self.device, (dims.x, dims.y), &mode) {
Ok((point_depth_stencil, directed_depth_stencil)) => {
shadow_map.point_depth_stencil = point_depth_stencil;
shadow_map.directed_depth_stencil = directed_depth_stencil;
Ok((point_depth, directed_depth)) => {
shadow_map.point_depth = point_depth;
shadow_map.directed_depth = directed_depth;
},
Err(err) => {
warn!("Could not create shadow map views: {:?}", err);
@ -496,7 +503,7 @@ impl Renderer {
};
let levels = 1;
let mut color_view = || {
let color_view = || {
let tex = device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
@ -527,7 +534,7 @@ impl Renderer {
let tgt_color_view = color_view();
let tgt_color_pp_view = color_view();
let tgt_depth_stencil_tex = device.create_texture(&wgpu::TextureDescriptor {
let tgt_depth_tex = device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width,
@ -540,17 +547,16 @@ impl Renderer {
format: wgpu::TextureFormat::Depth24Plus,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
});
let tgt_depth_stencil_view =
tgt_depth_stencil_tex.create_view(&wgpu::TextureViewDescriptor {
label: None,
format: Some(wgpu::TextureFormat::Depth24Plus),
dimension: Some(wgpu::TextureViewDimension::D2),
aspect: wgpu::TextureAspect::DepthOnly,
base_mip_level: 0,
level_count: None,
base_array_layer: 0,
array_layer_count: None,
});
let tgt_depth_view = tgt_depth_tex.create_view(&wgpu::TextureViewDescriptor {
label: None,
format: Some(wgpu::TextureFormat::Depth24Plus),
dimension: Some(wgpu::TextureViewDimension::D2),
aspect: wgpu::TextureAspect::DepthOnly,
base_mip_level: 0,
level_count: None,
base_array_layer: 0,
array_layer_count: None,
});
let win_depth_tex = device.create_texture(&wgpu::TextureDescriptor {
label: None,
@ -565,7 +571,7 @@ impl Renderer {
format: wgpu::TextureFormat::Depth24Plus,
usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
});
let win_depth_view = tgt_depth_stencil_tex.create_view(&wgpu::TextureViewDescriptor {
let win_depth_view = tgt_depth_tex.create_view(&wgpu::TextureViewDescriptor {
label: None,
format: Some(wgpu::TextureFormat::Depth24Plus),
dimension: Some(wgpu::TextureViewDimension::D2),
@ -578,7 +584,7 @@ impl Renderer {
Ok((
tgt_color_view,
tgt_depth_stencil_view,
tgt_depth_view,
tgt_color_pp_view,
win_depth_view,
))
@ -656,7 +662,7 @@ impl Renderer {
};
//TODO: (0, levels - 1), ?? from master
let mut point_shadow_view = wgpu::TextureViewDescriptor {
let point_shadow_view = wgpu::TextureViewDescriptor {
label: None,
format: Some(wgpu::TextureFormat::Depth24Plus),
dimension: Some(wgpu::TextureViewDimension::Cube),
@ -723,8 +729,8 @@ impl Renderer {
pub fn get_shadow_resolution(&self) -> (Vec2<u32>, Vec2<u32>) {
if let Some(shadow_map) = &self.shadow_map {
(
shadow_map.point_depth_stencil.get_dimensions().xy(),
shadow_map.directed_depth_stencil.get_dimensions().xy(),
shadow_map.point_depth.get_dimensions().xy(),
shadow_map.directed_depth.get_dimensions().xy(),
)
} else {
(Vec2::new(1, 1), Vec2::new(1, 1))
@ -741,10 +747,10 @@ impl Renderer {
// if let Some(shadow_map) = self.shadow_map.as_mut() {
// // let point_encoder = &mut shadow_map.point_encoder;
// let point_encoder = &mut self.encoder;
// point_encoder.clear_depth(&shadow_map.point_depth_stencil_view, 1.0);
// point_encoder.clear_depth(&shadow_map.point_depth_view, 1.0);
// // let directed_encoder = &mut shadow_map.directed_encoder;
// let directed_encoder = &mut self.encoder;
// directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view,
// directed_encoder.clear_depth(&shadow_map.directed_depth_view,
// 1.0); }
// }
@ -802,51 +808,20 @@ impl Renderer {
// }
// }
/// Perform all queued draw calls for this frame and clean up discarded
/// items.
pub fn flush(&mut self) -> Result<(), RenderError> {
span!(_guard, "flush", "Renderer::flush");
let frame = match self.swap_chain.get_current_frame() {
Ok(frame) => frame.output,
// If lost recreate the swap chain
Err(err @ wgpu::SwapChainError::Lost) => {
warn!("{}. Recreating swap chain. A frame will be missed", err);
return self.on_resize(self.resolution);
},
Err(err @ wgpu::SwapChainError::Timeout) => {
warn!("{}. This will probably be resolved on the next frame", err);
return Ok(());
},
Err(err @ wgpu::SwapChainError::Outdated) => {
warn!("{}. This will probably be resolved on the next frame", err);
return Ok(());
},
Err(err @ wgpu::SwapChainError::OutOfMemory) => return Err(err.into()),
};
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("A render encoder"),
});
{
let _render_pas = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &frame.view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.7,
b: 0.3,
a: 1.0,
}),
store: true,
},
}],
depth_stencil_attachment: None,
});
}
self.queue.submit(std::iter::once(encoder.finish()));
/// Start recording the frame
/// When the returned `Drawer` is dropped the recorded draw calls will be
/// submitted to the queue
/// If there is an intermittent issue with the swap chain then Ok(None) will
/// be returned
pub fn start_recording_frame<'a>(
&'a mut self,
globals: &'a GlobalsBindGroup,
) -> Result<Option<Drawer<'a>>, RenderError> {
span!(
_guard,
"start_recording_frame",
"Renderer::start_recording_frame"
);
self.device.poll(wgpu::Maintain::Poll);
@ -855,7 +830,30 @@ impl Renderer {
self.recreate_pipelines();
}
Ok(())
let tex = match self.swap_chain.get_current_frame() {
Ok(frame) => frame.output,
// If lost recreate the swap chain
Err(err @ wgpu::SwapChainError::Lost) => {
warn!("{}. Recreating swap chain. A frame will be missed", err);
return self.on_resize(self.resolution).map(|()| None);
},
Err(err @ wgpu::SwapChainError::Timeout) => {
warn!("{}. This will probably be resolved on the next frame", err);
return Ok(None);
},
Err(err @ wgpu::SwapChainError::Outdated) => {
warn!("{}. This will probably be resolved on the next frame", err);
return Ok(None);
},
Err(err @ wgpu::SwapChainError::OutOfMemory) => return Err(err.into()),
};
let encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("A render encoder"),
});
Ok(Some(Drawer::new(encoder, self, tex, globals)))
}
/// Recreate the pipelines
@ -916,14 +914,10 @@ impl Renderer {
}
/// Create a new set of constants with the provided values.
pub fn create_consts<T: Copy + bytemuck::Pod>(
&mut self,
vals: &[T],
// TODO: don't use result here
) -> Result<Consts<T>, RenderError> {
pub fn create_consts<T: Copy + bytemuck::Pod>(&mut self, vals: &[T]) -> Consts<T> {
let mut consts = Consts::new(&self.device, vals.len());
consts.update(&self.device, &self.queue, vals, 0);
Ok(consts)
consts
}
/// Update a set of constants with the provided values.
@ -1134,8 +1128,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1193,8 +1187,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1253,8 +1247,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (0, 0) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (0, 0) */), },
// ); */
// }
@ -1312,8 +1306,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1371,8 +1365,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1414,7 +1408,7 @@ impl Renderer {
// // Shadow stuff
// light_shadows: locals.buf.clone(),
// tgt_depth_stencil: shadow_map.point_depth_stencil_view.clone(),
// tgt_depth: shadow_map.point_depth_view.clone(),
// },
// );
// }
@ -1457,8 +1451,8 @@ impl Renderer {
// // Shadow stuff
// light_shadows: locals.buf.clone(),
// tgt_depth_stencil:
// shadow_map.directed_depth_stencil_view.clone(), },
// tgt_depth:
// shadow_map.directed_depth_view.clone(), },
// );
// }
@ -1503,8 +1497,8 @@ impl Renderer {
// // Shadow stuff
// light_shadows: locals.buf.clone(),
// tgt_depth_stencil:
// shadow_map.directed_depth_stencil_view.clone(), },
// tgt_depth:
// shadow_map.directed_depth_view.clone(), },
// );
// }
@ -1560,8 +1554,8 @@ impl Renderer {
// noise: (self.noise_tex.srv.clone(),
// self.noise_tex.sampler.clone()), waves: (waves.srv.clone(),
// waves.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1625,8 +1619,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1657,8 +1651,8 @@ impl Renderer {
// lod.map.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1711,8 +1705,8 @@ impl Renderer {
// self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(),
// lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(),
// lod.horizon.sampler.clone()), tgt_color:
// self.tgt_color_view.clone(), tgt_depth_stencil:
// (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), },
// self.tgt_color_view.clone(), tgt_depth:
// (self.tgt_depth_view.clone()/* , (1, 1) */), },
// );
// }
@ -1836,7 +1830,7 @@ fn create_pipelines(
fluid::FluidPipeline,
sprite::SpritePipeline,
particle::ParticlePipeline,
ui::UIPipeline,
ui::UiPipeline,
lod_terrain::LodTerrainPipeline,
clouds::CloudsPipeline,
postprocess::PostProcessPipeline,
@ -2029,7 +2023,7 @@ fn create_pipelines(
);
// Construct a pipeline for rendering UI elements
let ui_pipeline = ui::UIPipeline::new(
let ui_pipeline = ui::UiPipeline::new(
device,
&create_shader("ui-vert", ShaderKind::Vertex)?,
&create_shader("ui-frag", ShaderKind::Fragment)?,
@ -2077,7 +2071,7 @@ fn create_pipelines(
// let player_shadow_pipeline = create_pipeline(
// factory,
// figure::pipe::Init {
// tgt_depth_stencil: (gfx::preset::depth::PASS_TEST/*,
// tgt_depth: (gfx::preset::depth::PASS_TEST/*,
// Stencil::new(
// Comparison::Equal,
// 0xff,

View File

@ -0,0 +1,38 @@
use super::{
super::{
consts::Consts,
pipelines::{lod_terrain, ui, GlobalModel, GlobalsBindGroup},
texture::Texture,
},
Renderer,
};
impl Renderer {
pub fn bind_globals(
&self,
global_model: &GlobalModel,
lod_data: &lod_terrain::LodData,
) -> GlobalsBindGroup {
let (point_shadow_map, directed_shadow_map) = match &self.shadow_map {
Some(shadow_map) => (&shadow_map.point_depth, &shadow_map.directed_depth),
None => (&self.noise_tex, &self.noise_tex),
};
self.layouts.global.bind(
&self.device,
global_model,
lod_data,
&self.noise_tex,
point_shadow_map,
directed_shadow_map,
)
}
pub fn ui_bind_locals(&self, locals: &Consts<ui::Locals>) -> ui::LocalsBindGroup {
self.layouts.ui.bind_locals(&self.device, locals)
}
pub fn ui_bind_texture(&self, texture: &Texture) -> ui::TextureBindGroup {
self.layouts.ui.bind_texture(&self.device, texture)
}
}

View File

@ -0,0 +1,360 @@
use super::{
super::{
buffer::Buffer,
consts::Consts,
instances::Instances,
model::{DynamicModel, Model},
pipelines::{
figure, fluid, postprocess, sprite, terrain, ui, GlobalsBindGroup, Light, Shadow,
},
},
Renderer,
};
use std::ops::Range;
use vek::Aabr;
pub struct Drawer<'a> {
encoder: Option<wgpu::CommandEncoder>,
renderer: &'a mut Renderer,
tex: wgpu::SwapChainTexture,
globals: &'a GlobalsBindGroup,
//pub(super) postprocess_locals: wgpu::BindGroup,
}
impl<'a> Drawer<'a> {
pub fn new(
encoder: wgpu::CommandEncoder,
renderer: &'a mut Renderer,
tex: wgpu::SwapChainTexture,
globals: &'a GlobalsBindGroup,
) -> Self {
Self {
encoder: Some(encoder),
renderer,
tex,
globals,
}
}
/*pub fn first_pass(&mut self) -> FirstPassDrawer {
let render_pass =
self.encoder
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &self.renderer.tgt_color_view,
resolve_target: None,
load_op: wgpu::LoadOp::Clear,
store_op: wgpu::StoreOp::Store,
clear_color: wgpu::Color::TRANSPARENT,
}],
depth_stencil_attachment: Some(
wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment: &self.renderer.depth_stencil_texture.view,
depth_load_op: wgpu::LoadOp::Clear,
depth_store_op: wgpu::StoreOp::Store,
clear_depth: 1.0,
stencil_load_op: wgpu::LoadOp::Clear,
stencil_store_op: wgpu::StoreOp::Store,
clear_stencil: 0,
},
),
});
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
FirstPassDrawer {
render_pass,
renderer: &self.renderer,
}
}
pub fn second_pass(&mut self) -> SecondPassDrawer {
let render_pass =
self.encoder
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &self.renderer.tgt_color_pp_view,
resolve_target: None,
load_op: wgpu::LoadOp::Clear,
store_op: wgpu::StoreOp::Store,
clear_color: wgpu::Color::TRANSPARENT,
}],
depth_stencil_attachment: None,
});
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
SecondPassDrawer {
render_pass,
renderer: &self.renderer,
}
}*/
pub fn third_pass(&mut self) -> ThirdPassDrawer {
let mut render_pass =
self.encoder
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &self.tex.view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 1.0,
g: 0.25,
b: 0.5,
a: 0.5,
}),
store: true,
},
}],
// TODO: do we need this?
depth_stencil_attachment: Some(
wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment: &self.renderer.win_depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: true,
}),
stencil_ops: None,
},
),
});
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
ThirdPassDrawer {
render_pass,
renderer: &self.renderer,
//postprocess_locals: &self.postprocess_locals,
}
}
}
impl<'a> Drop for Drawer<'a> {
fn drop(&mut self) {
self.renderer
.queue
.submit(std::iter::once(self.encoder.take().unwrap().finish()));
}
}
/*pub struct FirstPassDrawer<'a> {
pub(super) render_pass: wgpu::RenderPass<'a>,
pub renderer: &'a Renderer,
}
impl<'a> FirstPassDrawer<'a> {
pub fn draw_skybox<'b: 'a>(
&mut self,
model: &'b Model,
globals: &'b Consts<Globals>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.skybox_pipeline.pipeline);
self.render_pass.set_bind_group(0, &globals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0);
self.render_pass.draw(verts, 0..1);
}
pub fn draw_figure<'b: 'a>(
&mut self,
model: &'b Model,
locals: &'b Consts<figure::Locals>,
bones: &'b Consts<figure::BoneData>,
globals: &'b Consts<Globals>,
lights: &'b Consts<Light>,
shadows: &'b Consts<Shadow>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.figure_pipeline.pipeline);
self.render_pass.set_bind_group(0, &globals.bind_group, &[]);
self.render_pass.set_bind_group(1, &lights.bind_group, &[]);
self.render_pass.set_bind_group(2, &shadows.bind_group, &[]);
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
self.render_pass.set_bind_group(4, &bones.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0);
self.render_pass.draw(verts, 0..1);
}
pub fn draw_terrain<'b: 'a>(
&mut self,
model: &'b Model,
locals: &'b Consts<terrain::Locals>,
globals: &'b Consts<Globals>,
lights: &'b Consts<Light>,
shadows: &'b Consts<Shadow>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.terrain_pipeline.pipeline);
self.render_pass.set_bind_group(0, &globals.bind_group, &[]);
self.render_pass.set_bind_group(1, &lights.bind_group, &[]);
self.render_pass.set_bind_group(2, &shadows.bind_group, &[]);
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0);
self.render_pass.draw(verts, 0..1)
}
pub fn draw_fluid<'b: 'a>(
&mut self,
model: &'b Model,
locals: &'b Consts<terrain::Locals>,
waves: &'b Consts<fluid::Locals>,
globals: &'b Consts<Globals>,
lights: &'b Consts<Light>,
shadows: &'b Consts<Shadow>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.fluid_pipeline.pipeline);
self.render_pass.set_bind_group(0, &globals.bind_group, &[]);
self.render_pass.set_bind_group(1, &lights.bind_group, &[]);
self.render_pass.set_bind_group(2, &shadows.bind_group, &[]);
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
self.render_pass.set_bind_group(4, &waves.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0);
self.render_pass.draw(verts, 0..1);
}
pub fn draw_sprite<'b: 'a>(
&mut self,
model: &'b Model,
instances: &'a Instances<sprite::Instance>,
globals: &'b Consts<Globals>,
lights: &'b Consts<Light>,
shadows: &'b Consts<Shadow>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.sprite_pipeline.pipeline);
self.render_pass.set_bind_group(0, &globals.bind_group, &[]);
self.render_pass.set_bind_group(1, &lights.bind_group, &[]);
self.render_pass.set_bind_group(2, &shadows.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0);
self.render_pass.set_vertex_buffer(1, &instances.ibuf, 0, 0);
self.render_pass.draw(verts, 0..instances.count() as u32);
}
}
pub struct SecondPassDrawer<'a> {
pub(super) render_pass: wgpu::RenderPass<'a>,
pub renderer: &'a Renderer,
}
impl<'a> SecondPassDrawer<'a> {
pub fn draw_post_process<'b: 'a>(
&mut self,
model: &'b Model,
globals: &'b Consts<Globals>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.postprocess_pipeline.pipeline);
self.render_pass.set_bind_group(0, &globals.bind_group, &[]);
self.render_pass
.set_bind_group(1, self.postprocess_locals, &[]);
self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0);
self.render_pass.draw(verts, 0..1);
}
}*/
pub struct ThirdPassDrawer<'a> {
render_pass: wgpu::RenderPass<'a>,
renderer: &'a Renderer,
//postprocess_locals: &'a wgpu::BindGroup,
}
impl<'a> ThirdPassDrawer<'a> {
pub fn draw_post_process<'b: 'a>(
&mut self,
model: &'b Model<postprocess::Vertex>,
verts: Range<u32>,
) {
self.render_pass
.set_pipeline(&self.renderer.postprocess_pipeline.pipeline);
//self.render_pass
// .set_bind_group(1, self.postprocess_locals, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(verts, 0..1);
}
pub fn draw_ui<'c>(&'c mut self) -> UiDrawer<'c, 'a> {
self.render_pass
.set_pipeline(&self.renderer.ui_pipeline.pipeline);
UiDrawer {
render_pass: &mut self.render_pass,
}
}
}
pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> {
/// Set vertex buffer, initial scissor, and locals
/// These can be changed later but this ensures that they don't have to be
/// set with every draw call
pub fn prepare<'data: 'pass>(
&mut self,
locals: &'data ui::LocalsBindGroup,
//texture: &'b ui::TextureBindGroup,
buf: &'data DynamicModel<ui::Vertex>,
scissor: Aabr<u16>,
) -> PreparedUiDrawer<'_, 'pass> {
// Note: not actually prepared yet
// we do this to avoid having to write extra code for the set functions
let mut prepared = PreparedUiDrawer {
render_pass: self.render_pass,
};
// Prepare
prepared.set_locals(locals);
//prepared.set_texture(texture);
prepared.set_model(buf);
prepared.set_scissor(scissor);
prepared
}
}
impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> {
pub fn set_locals<'data: 'pass>(&mut self, locals: &'data ui::LocalsBindGroup) {
self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
}
//pub fn set_texture<'b: 'a>(&mut self, texture: &'b ui::TextureBindGroup) {
// self.render_pass.set_bind_group(1, &texture.bind_group, &[]);
//}
pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel<ui::Vertex>) {
self.render_pass.set_vertex_buffer(0, model.buf().slice(..))
}
pub fn set_scissor<'data: 'pass>(&mut self, scissor: Aabr<u16>) {
let Aabr { min, max } = scissor;
//self.render_pass.set_scissor_rect(
// min.x as u32,
// min.y as u32,
// (max.x - min.x) as u32,
// (max.y - min.y) as u32,
//);
}
pub fn draw<'data: 'pass>(&mut self, texture: &'data ui::TextureBindGroup, verts: Range<u32>) {
self.render_pass.set_bind_group(2, &texture.bind_group, &[]);
self.render_pass.draw(verts, 0..1);
}
}

View File

@ -179,7 +179,7 @@ impl Texture {
data: &[u8],
) {
// Note: we only accept 4 bytes per pixel
// (enforce this is API?)
// (enforce this in API?)
debug_assert_eq!(data.len(), size[0] as usize * size[1] as usize * 4);
// TODO: Only works for 2D images
queue.write_texture(

View File

@ -176,7 +176,7 @@ fn handle_main_events_cleared(
last.render(renderer, &global_state.settings);
// Finish the frame.
// TODO: do this as part of dropping rendering thing
global_state.window.renderer_mut().flush().unwrap();
//global_state.window.renderer_mut().flush().unwrap();
// // Display the frame on the window.
// global_state
// .window

View File

@ -8,13 +8,13 @@ use crate::{
ecs::comp::Interpolated,
render::{
pipelines, ColLightInfo, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel,
Mesh, RenderError, Renderer, SubModel, TerrainVertex, Texture,
LodData, Mesh, RenderError, Renderer, SubModel, TerrainVertex, Texture,
},
scene::{
camera::{Camera, CameraMode, Dependents},
math,
terrain::Terrain,
LodData, SceneData,
SceneData,
},
};
use anim::{
@ -5352,8 +5352,8 @@ impl<S: Skeleton> FigureState<S> {
let bone_consts = figure_bone_data_from_anim(&buf);
Self {
meta: FigureStateMeta {
bone_consts: renderer.create_consts(bone_consts).unwrap(),
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
bone_consts: renderer.create_consts(bone_consts),
locals: renderer.create_consts(&[FigureLocals::default()]),
lantern_offset,
state_time: 0.0,
last_ori: Ori::default().into(),

View File

@ -17,8 +17,8 @@ use crate::{
audio::{ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend},
render::{
create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsVertex, Consts,
GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, PostProcessVertex,
Renderer, Shadow, ShadowLocals, SkyboxVertex,
GlobalModel, Globals, Light, Model, PostProcessLocals, PostProcessVertex, Renderer, Shadow,
ShadowLocals, SkyboxVertex,
},
settings::Settings,
window::{AnalogGameInput, Event},
@ -277,16 +277,11 @@ impl Scene {
Self {
data: GlobalModel {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
lights: renderer
.create_consts(&[Light::default(); MAX_LIGHT_COUNT])
.unwrap(),
shadows: renderer
.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT])
.unwrap(),
globals: renderer.create_consts(&[Globals::default()]),
lights: renderer.create_consts(&[Light::default(); MAX_LIGHT_COUNT]),
shadows: renderer.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]),
shadow_mats: renderer
.create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6])
.unwrap(),
.create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6]),
},
camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson),
camera_input_state: Vec2::zero(),
@ -297,13 +292,11 @@ impl Scene {
},
clouds: Clouds {
model: renderer.create_model(&create_clouds_mesh()).unwrap(),
locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(),
locals: renderer.create_consts(&[CloudsLocals::default()]),
},
postprocess: PostProcess {
model: renderer.create_model(&create_pp_mesh()).unwrap(),
locals: renderer
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
locals: renderer.create_consts(&[PostProcessLocals::default()]),
},
terrain: Terrain::new(renderer, sprite_render_context),
lod: Lod::new(renderer, client, settings),

View File

@ -2,14 +2,13 @@ use crate::{
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain},
render::{
create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals,
CloudsVertex, Consts, FigureModel, GlobalModel, Globals, Light, Mesh, Model,
CloudsVertex, Consts, FigureModel, GlobalModel, Globals, Light, LodData, Mesh, Model,
PostProcessLocals, PostProcessVertex, Renderer, Shadow, ShadowLocals, SkyboxVertex,
TerrainVertex,
},
scene::{
camera::{self, Camera, CameraMode},
figure::{load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState},
LodData,
},
window::{Event, PressState},
};
@ -110,10 +109,6 @@ impl Scene {
client.world_data().min_chunk_alt(),
client.world_data().max_chunk_alt(),
);
let map_border = [0.0, 0.0, 0.0, 0.0];
let map_image = [0];
let alt_image = [0];
let horizon_image = [0x_00_01_00_01];
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
camera.set_focus_pos(Vec3::unit_z() * 1.5);
@ -124,12 +119,10 @@ impl Scene {
Self {
data: GlobalModel {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
shadows: renderer.create_consts(&[Shadow::default(); 32]).unwrap(),
shadow_mats: renderer
.create_consts(&[ShadowLocals::default(); 6])
.unwrap(),
globals: renderer.create_consts(&[Globals::default()]),
lights: renderer.create_consts(&[Light::default(); 32]),
shadows: renderer.create_consts(&[Shadow::default(); 32]),
shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]),
},
skybox: Skybox {
@ -137,23 +130,13 @@ impl Scene {
},
clouds: Clouds {
model: renderer.create_model(&create_clouds_mesh()).unwrap(),
locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(),
locals: renderer.create_consts(&[CloudsLocals::default()]),
},
postprocess: PostProcess {
model: renderer.create_model(&create_pp_mesh()).unwrap(),
locals: renderer
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
locals: renderer.create_consts(&[PostProcessLocals::default()]),
},
lod: LodData::new(
renderer,
Vec2::new(1, 1),
&map_image,
&alt_image,
&horizon_image,
1,
//map_border.into(),
),
lod: LodData::dummy(renderer),
map_bounds,
figure_model_cache: FigureModelCache::new(),

View File

@ -8,13 +8,13 @@ use crate::{
terrain::{generate_mesh, SUNLIGHT},
},
render::{
pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, Mesh, Model,
pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, LodData, Mesh, Model,
RenderError, Renderer, SpriteInstance, SpriteLocals, SpriteVertex, TerrainLocals,
TerrainVertex, Texture,
},
};
use super::{math, LodData, SceneData};
use super::{math, SceneData};
use common::{
assets::{self, AssetExt, DotVoxAsset},
figure::Segment,
@ -517,9 +517,7 @@ impl SpriteRenderContext {
offset,
}| {
SpriteData {
locals: renderer
.create_consts(&locals)
.expect("Failed to upload sprite locals to the GPU!"),
locals: renderer.create_consts(&locals_buffer),
model: renderer.create_model(&model).expect(
"Failed to upload sprite model data to the GPU!",
),
@ -1161,24 +1159,22 @@ impl<V: RectRasterableVol> Terrain<V> {
light_map: mesh.light_map,
glow_map: mesh.glow_map,
sprite_instances,
locals: renderer
.create_consts(&[TerrainLocals {
model_offs: Vec3::from(
response.pos.map2(VolGrid2d::<V>::chunk_size(), |e, sz| {
e as f32 * sz as f32
}),
)
.into_array(),
atlas_offs: Vec4::new(
atlas_offs.x as i32,
atlas_offs.y as i32,
0,
0,
)
.into_array(),
load_time,
}])
.expect("Failed to upload chunk locals to the GPU!"),
locals: renderer.create_consts(&[TerrainLocals {
model_offs: Vec3::from(
response.pos.map2(VolGrid2d::<V>::chunk_size(), |e, sz| {
e as f32 * sz as f32
}),
)
.into_array(),
atlas_offs: Vec4::new(
atlas_offs.x as i32,
atlas_offs.y as i32,
0,
0,
)
.into_array(),
load_time,
}]),
visible: Visibility {
in_range: false,
in_frustum: false,

View File

@ -3,7 +3,7 @@ mod renderer;
pub use renderer::{SampleStrat, Transform};
use crate::render::{Renderer, Texture};
use crate::render::{Renderer, Texture, UiTextureBindGroup};
use common::figure::Segment;
use guillotiere::{size2, SimpleAtlasAllocator};
use hashbrown::{hash_map::Entry, HashMap};
@ -139,7 +139,7 @@ pub struct GraphicCache {
// Atlases with the index of their texture in the textures vec
atlases: Vec<(SimpleAtlasAllocator, usize)>,
textures: Vec<Texture>,
textures: Vec<(Texture, UiTextureBindGroup)>,
// Stores the location of graphics rendered at a particular resolution and cached on the cpu
cache_map: HashMap<Parameters, CachedDetails>,
}
@ -184,7 +184,7 @@ impl GraphicCache {
pub fn get_graphic(&self, id: Id) -> Option<&Graphic> { self.graphic_map.get(&id) }
/// Used to acquire textures for rendering
pub fn get_tex(&self, id: TexId) -> &Texture {
pub fn get_tex(&self, id: TexId) -> &(Texture, UiTextureBindGroup) {
self.textures.get(id.0).expect("Invalid TexId used")
}
@ -284,7 +284,7 @@ impl GraphicCache {
// color.
assert!(border.is_none());
// Transfer to the gpu
upload_image(renderer, aabr, &textures[idx], &image);
upload_image(renderer, aabr, &textures[idx].0, &image);
}
return Some((transformed_aabr(aabr.map(|e| e as f64)), TexId(idx)));
@ -324,7 +324,7 @@ impl GraphicCache {
valid: true,
aabr,
});
upload_image(renderer, aabr, &textures[texture_idx], &image);
upload_image(renderer, aabr, &textures[texture_idx].0, &image);
break;
}
}
@ -344,7 +344,7 @@ impl GraphicCache {
let atlas_idx = atlases.len();
textures.push(texture);
atlases.push((atlas, tex_idx));
upload_image(renderer, aabr, &textures[tex_idx], &image);
upload_image(renderer, aabr, &textures[tex_idx].0, &image);
CachedDetails::Atlas {
atlas_idx,
valid: true,
@ -354,7 +354,11 @@ impl GraphicCache {
}
} else {
// Create a texture just for this
let texture = renderer.create_dynamic_texture(dims.map(|e| e as u32));
let texture = {
let tex = renderer.create_dynamic_texture(dims.map(|e| e as u32));
let bind = renderer.ui_bind_texture(&tex);
(tex, bind)
};
// NOTE: All mutations happen only after the texture creation succeeds!
let index = textures.len();
textures.push(texture);
@ -365,7 +369,7 @@ impl GraphicCache {
// Note texture should always match the cached dimensions
max: dims,
},
&textures[index],
&textures[index].0,
&image,
);
CachedDetails::Texture { index, valid: true }
@ -419,11 +423,18 @@ fn atlas_size(renderer: &Renderer) -> Vec2<u32> {
})
}
fn create_atlas_texture(renderer: &mut Renderer) -> (SimpleAtlasAllocator, Texture) {
fn create_atlas_texture(
renderer: &mut Renderer,
) -> (SimpleAtlasAllocator, (Texture, UiTextureBindGroup)) {
let size = atlas_size(renderer);
// Note: here we assume the atlas size is under i32::MAX
let atlas = SimpleAtlasAllocator::new(size2(size.x as i32, size.y as i32));
let texture = renderer.create_dynamic_texture(size);
let texture = {
let tex = renderer.create_dynamic_texture(size);
let bind = renderer.ui_bind_texture(&tex);
(tex, bind)
};
(atlas, texture)
}
@ -449,8 +460,12 @@ fn upload_image(renderer: &mut Renderer, aabr: Aabr<u16>, tex: &Texture, image:
);
}
fn create_image(renderer: &mut Renderer, image: RgbaImage, border_color: Rgba<f32>) -> Texture {
renderer
fn create_image(
renderer: &mut Renderer,
image: RgbaImage,
border_color: Rgba<f32>,
) -> (Texture, UiTextureBindGroup) {
let tex = renderer
.create_texture(
&DynamicImage::ImageRgba8(image),
None,
@ -458,5 +473,8 @@ fn create_image(renderer: &mut Renderer, image: RgbaImage, border_color: Rgba<f3
// Some(border_color.into_array().into()),
Some(wgpu::AddressMode::ClampToBorder),
)
.expect("create_texture only panics is non ImageRbga8 is passed")
.expect("create_texture only panics is non ImageRbga8 is passed");
let bind = renderer.ui_bind_texture(&tex);
(tex, bind)
}

View File

@ -1,6 +1,6 @@
use super::graphic::{Graphic, GraphicCache, Id as GraphicId};
use crate::{
render::{Renderer, Texture},
render::{Renderer, Texture, UiTextureBindGroup},
Error,
};
use common::assets::{self, AssetExt};
@ -46,7 +46,7 @@ pub struct FontId(pub(super) glyph_brush::FontId);
pub struct Cache {
glyph_brush: RefCell<GlyphBrush>,
glyph_cache_tex: Texture,
glyph_cache_tex: (Texture, UiTextureBindGroup),
graphic_cache: GraphicCache,
}
@ -66,16 +66,22 @@ impl Cache {
.draw_cache_position_tolerance(POSITION_TOLERANCE)
.build();
let glyph_cache_tex = {
let tex = renderer.create_dynamic_texture(glyph_cache_dims);
let bind = renderer.ui_bind_texture(&tex);
(tex, bind)
};
Ok(Self {
glyph_brush: RefCell::new(glyph_brush),
glyph_cache_tex: renderer.create_dynamic_texture(glyph_cache_dims),
glyph_cache_tex,
graphic_cache: GraphicCache::new(renderer),
})
}
pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex }
pub fn glyph_cache_tex(&self) -> &(Texture, UiTextureBindGroup) { &self.glyph_cache_tex }
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &Texture) {
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &(Texture, UiTextureBindGroup)) {
(self.glyph_brush.get_mut(), &self.glyph_cache_tex)
}
@ -117,6 +123,7 @@ impl Cache {
self.graphic_cache.replace_graphic(id, graphic)
}
// TODO: combine resize functions
// Resizes and clears the GraphicCache
pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) {
self.graphic_cache.clear_cache(renderer);
@ -134,7 +141,12 @@ impl Cache {
.initial_cache_size((cache_dims.x, cache_dims.y))
.build();
self.glyph_cache_tex = renderer.create_dynamic_texture(cache_dims);
self.glyph_cache_tex = {
let tex = renderer.create_dynamic_texture(cache_dims);
let bind = renderer.ui_bind_texture(&tex);
(tex, bind)
};
Ok(())
}
}

View File

@ -14,7 +14,11 @@ use super::{
graphic::{self, Graphic},
scale::{Scale, ScaleMode},
};
use crate::{render::Renderer, window::Window, Error};
use crate::{
render::{Renderer, UiDrawer},
window::Window,
Error,
};
use common_base::span;
use iced::{mouse, Cache, Size, UserInterface};
use iced_winit::Clipboard;
@ -212,5 +216,5 @@ impl IcedUi {
(messages, mouse_interaction)
}
pub fn render(&self, renderer: &mut Renderer) { self.renderer.render(renderer, None); }
pub fn render<'a>(&'a self, drawer: &mut UiDrawer<'_, 'a>) { self.renderer.render(drawer); }
}

View File

@ -15,8 +15,8 @@ use super::{
};
use crate::{
render::{
create_ui_quad, create_ui_quad_vert_gradient, Consts, DynamicModel, Globals, Mesh,
Renderer, UiLocals, UiMode, UiVertex,
create_ui_quad, create_ui_quad_vert_gradient, Consts, DynamicModel, Mesh, Renderer,
UiDrawer, UiLocals, UiLocalsBindGroup, UiMode, UiVertex,
},
Error,
};
@ -85,10 +85,10 @@ pub struct IcedRenderer {
// Model for drawing the ui
model: DynamicModel<UiVertex>,
// Consts to specify positions of ingame elements (e.g. Nametags)
ingame_locals: Vec<Consts<UiLocals>>,
ingame_locals: Vec<(Consts<UiLocals>, UiLocalsBindGroup)>,
// Consts for default ui drawing position (ie the interface)
interface_locals: Consts<UiLocals>,
default_globals: Consts<Globals>,
interface_locals: (Consts<UiLocals>, UiLocalsBindGroup),
//default_globals: Consts<Globals>,
// Used to delay cache resizing until after current frame is drawn
//need_cache_resize: bool,
@ -125,12 +125,18 @@ impl IcedRenderer {
let (half_res, align, p_scale) =
Self::calculate_resolution_dependents(physical_resolution, scaled_resolution);
let interface_locals = {
let locals = renderer.create_consts(&[UiLocals::default()]);
let bind = renderer.ui_bind_locals(&locals);
(locals, bind)
};
Ok(Self {
cache: Cache::new(renderer, default_font)?,
draw_commands: Vec::new(),
model: renderer.create_dynamic_model(100),
interface_locals: renderer.create_consts(&[UiLocals::default()])?,
default_globals: renderer.create_consts(&[Globals::default()])?,
interface_locals,
//default_globals: renderer.create_consts(&[Globals::default()]),
ingame_locals: Vec::new(),
mesh: Mesh::new(),
glyphs: Vec::new(),
@ -222,7 +228,7 @@ impl IcedRenderer {
.push(DrawCommand::plain(self.start..self.mesh.vertices().len()));*/
// Fill in placeholder glyph quads
let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
let (glyph_cache, (cache_tex, _)) = self.cache.glyph_cache_mut_and_tex();
let half_res = self.half_res;
let brush_result = glyph_cache.process_queued(
@ -542,6 +548,7 @@ impl IcedRenderer {
Some((aabr, tex_id)) => {
let cache_dims = graphic_cache
.get_tex(tex_id)
.0
.get_dimensions()
.xy()
.map(|e| e as f32);
@ -763,28 +770,32 @@ impl IcedRenderer {
}
}
pub fn render(&self, renderer: &mut Renderer, maybe_globals: Option<&Consts<Globals>>) {
pub fn render<'pass_ref, 'pass: 'pass_ref, 'data: 'pass>(
&'data self,
drawer: &mut UiDrawer<'pass_ref, 'pass>, /* maybe_globals: Option<&Consts<Globals>> */
) {
span!(_guard, "render", "IcedRenderer::render");
let mut scissor = self.window_scissor;
let globals = maybe_globals.unwrap_or(&self.default_globals);
let mut locals = &self.interface_locals;
let mut drawer = drawer.prepare(&self.interface_locals.1, &self.model, self.window_scissor);
//let mut scissor = self.window_scissor;
//let globals = maybe_globals.unwrap_or(&self.default_globals);
//let mut locals = &self.interface_locals.1;
for draw_command in self.draw_commands.iter() {
match draw_command {
DrawCommand::Scissor(new_scissor) => {
scissor = *new_scissor;
drawer.set_scissor(*new_scissor);
},
DrawCommand::WorldPos(index) => {
locals = index.map_or(&self.interface_locals, |i| &self.ingame_locals[i]);
drawer.set_locals(
index.map_or(&self.interface_locals.1, |i| &self.ingame_locals[i].1),
);
},
DrawCommand::Draw { kind, verts } => {
// TODO: don't make these assert!(!verts.is_empty());
let tex = match kind {
DrawKind::Image(tex_id) => self.cache.graphic_cache().get_tex(*tex_id),
DrawKind::Plain => self.cache.glyph_cache_tex(),
};
let model = self.model.submodel(verts.clone());
// TODO
//renderer.render_ui_element(model, tex, scissor, globals,
// locals);
drawer.draw(&tex.1, verts.clone()); // Note: trivial clone
},
}
}

View File

@ -163,8 +163,8 @@ impl Ui {
draw_commands: Vec::new(),
mesh: Mesh::new(),
model: renderer.create_dynamic_model(100),
interface_locals: renderer.create_consts(&[UiLocals::default()])?,
default_globals: renderer.create_consts(&[Globals::default()])?,
interface_locals: renderer.create_consts(&[UiLocals::default()]),
default_globals: renderer.create_consts(&[Globals::default()]),
ingame_locals: Vec::new(),
window_resized: None,
scale_factor_changed: None,
@ -812,6 +812,7 @@ impl Ui {
Some((aabr, tex_id)) => {
let cache_dims = graphic_cache
.get_tex(tex_id)
.0
.get_dimensions()
.xy()
.map(|e| e as f32);
@ -953,7 +954,7 @@ impl Ui {
)
} else {
self.ingame_locals
.push(renderer.create_consts(&[world_pos.into()]).unwrap());
.push(renderer.create_consts(&[world_pos.into()]));
}
self.draw_commands
.push(DrawCommand::WorldPos(Some(ingame_local_index)));
@ -1019,11 +1020,12 @@ impl Ui {
locals = index.map_or(&self.interface_locals, |i| &self.ingame_locals[i]);
},
DrawCommand::Draw { kind, verts } => {
let tex = match kind {
DrawKind::Image(tex_id) => self.cache.graphic_cache().get_tex(*tex_id),
DrawKind::Plain => self.cache.glyph_cache_tex(),
};
let model = self.model.submodel(verts.clone());
//let tex = match kind {
// DrawKind::Image(tex_id) =>
// self.cache.graphic_cache().get_tex(*tex_id),
// DrawKind::Plain => self.cache.glyph_cache_tex(),
//};
//let model = self.model.submodel(verts.clone());
// TODO
//renderer.render_ui_element(model, tex, scissor, globals,
// locals);