use rin_gl as gl;
use generational_arena::{self as arena, Arena};
use std::ops::{Index, IndexMut};
use rinecs::{EntitiesThreadLocal, OneToNComponent, Read, ReadOption, ResourcesThreadLocal, Sto, StorageRef, SystemThreadLocal, UnorderedData, Write, system_thread_local};
use crate::light::{shadow, Light};
use crate::DeferredScene;
use super::{ProgramCache, ShadowMaterialCache, geometry::{
ShadowGeometry, GpuGeometryRef,
AllShadowsCommandBuffer, AllShadowsCommandBufferData,
StaticShadowsCommandBuffer, StaticShadowsCommandBufferData,
ShadowsCommandBuffer, ShadowsCommandBufferData, Segment
}, light::LightAsCameraUBO, material::ShadowMaterialOffsets, memory::AllocatorsIndex, renderer::{RendererType}, resources};
use rin_math::{pnt2, Pnt2, Rect, Mat4};
use rect_packer::DensePacker;
use densevec::DenseVec;
use glin::CreationContext as _;
use glin::SurfaceCreationContext;
use itertools::Itertools;
use std::marker::PhantomData;
use std::mem;
use rin_util::Result;
use rin_graphics::Node;
use std::ops::Deref;
#[derive(OneToNComponent, Debug)]
#[debug_as_string]
pub struct Map{
pub(crate) map: ShadowMapRef,
pub(crate) needs_update: bool,
}
#[derive(OneToNComponent, Debug)]
#[debug_as_string]
pub struct StaticMap(pub(crate) ShadowMapRef);
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ShadowMapRef(arena::Index);
pub struct ShadowMapView{
index: usize,
x: u32,
y: u32,
settings: shadow::Parameters,
}
impl ShadowMapView{
pub fn viewport(&self) -> Rect<i32>{
Rect{
pos: pnt2(self.x as i32, self.y as i32),
width: self.settings.map_size as i32,
height: self.settings.map_size as i32,
}
}
}
struct MegaShadowMap{
depth_buffers: Vec<glin::Fbo>,
shadow_sampler: glin::Sampler,
debug_draw_sampler: glin::Sampler,
occupancy_map: Vec<DensePacker>,
}
impl MegaShadowMap{
fn new(gl: &gl::CreationProxy, size: u32, resolution: glin::fbo::DepthFormat) -> Result<MegaShadowMap> {
let max_texture_size = gl.capabilities().max_texture_size;
let num_textures_required = (size as f32 / max_texture_size as f32).ceil() as u32;
let texture_size = if max_texture_size >= size { size } else { max_texture_size };
let mut depth_buffers = (0..num_textures_required).map(|_| {
let depth_texture = gl
.new_fbo_depth_attachment()
.texture(texture_size as u32, texture_size as u32, resolution)
.unwrap();
gl.new_fbo().from_depth(depth_texture).unwrap()
}).collect::<Vec<_>>();
let occupancy_map = (0..num_textures_required).map(|_|{
DensePacker::new(texture_size as i32, texture_size as i32)
}).collect();
for fbo in depth_buffers.iter_mut() {
let fbo_tex = fbo.depth_tex_mut().unwrap();
#[cfg(not(feature = "webgl"))]
fbo_tex.set_swizzles(gl::texture::Swizzles::r_to_rgb());
#[cfg(not(feature = "webgl"))]
fbo_tex.set_min_mag_filters(gl::LINEAR, gl::LINEAR);
#[cfg(feature = "webgl")]
fbo_tex.set_min_mag_filters(gl::NEAREST, gl::NEAREST);
fbo_tex.set_wrap_s(gl::CLAMP_TO_EDGE);
fbo_tex.set_wrap_t(gl::CLAMP_TO_EDGE);
}
let mut debug_draw_sampler = gl.new_sampler();
#[cfg(not(feature = "webgl"))]
debug_draw_sampler.set_min_mag_filters(gl::NEAREST, gl::NEAREST);
#[cfg(feature = "webgl")]
debug_draw_sampler.set_min_mag_filters(gl::NEAREST, gl::NEAREST);
debug_draw_sampler.set_wrap_s(gl::CLAMP_TO_EDGE);
debug_draw_sampler.set_wrap_t(gl::CLAMP_TO_EDGE);
debug_draw_sampler.set_compare_mode(gl::NONE);
let mut shadow_sampler = gl.new_sampler();
#[cfg(not(feature = "webgl"))]
shadow_sampler.set_min_mag_filters(gl::LINEAR, gl::LINEAR);
#[cfg(feature = "webgl")]
shadow_sampler.set_min_mag_filters(gl::NEAREST, gl::NEAREST);
shadow_sampler.set_wrap_s(gl::CLAMP_TO_EDGE);
shadow_sampler.set_wrap_t(gl::CLAMP_TO_EDGE);
shadow_sampler.set_compare_mode(gl::COMPARE_REF_TO_TEXTURE);
shadow_sampler.set_compare_func(gl::LEQUAL);
Ok(MegaShadowMap{
depth_buffers,
debug_draw_sampler,
shadow_sampler,
occupancy_map,
})
}
fn find_free_space(&mut self, size: u16) -> Option<(usize, Pnt2<u32>)>{
for (map_idx, map) in self.occupancy_map.iter_mut().enumerate(){
if let Some(rect) = map.pack(size as i32, size as i32, false){
return Some((map_idx, pnt2(rect.x as u32, rect.y as u32)))
}
}
None
}
fn allocate_shadow_map(&mut self, settings: shadow::Parameters) -> Option<ShadowMapView>{
self.find_free_space(settings.map_size).map(move |(index, pos)|{
ShadowMapView{
index,
x: pos.x,
y: pos.y,
settings,
}
})
}
fn reset_occupancy_map(&mut self) {
let (w,_h) = self.occupancy_map[0].size();
let levels = self.occupancy_map.len();
self.occupancy_map = (0..levels).map(|_| DensePacker::new(w,w)).collect();
}
}
pub struct ShadowMapPool {
creation_proxy: gl::CreationProxy,
mega_shadow_maps: DenseVec<MegaShadowMap>,
max_texture_size: u32,
index: Arena<ShadowMapView>
}
impl ShadowMapPool {
pub fn new(gl: &gl::Renderer) -> ShadowMapPool {
let max_texture_size = gl.capabilities().max_texture_size / 2;
let creation_proxy = gl.creation_proxy();
ShadowMapPool {
creation_proxy,
mega_shadow_maps: DenseVec::new(),
index: Arena::new(),
max_texture_size,
}
}
pub fn allocate_shadow_map(&mut self, parameters: shadow::Parameters) -> Option<ShadowMapRef>{
let gl = &self.creation_proxy;
let atlas_size = self.atlas_size();
let mega_shadow_map = &mut self.mega_shadow_maps
.entry(parameters.resolution as usize)
.or_insert_with(|| {
let format = match parameters.resolution {
shadow::Resolution::_16 => gl::fbo::DepthFormat::_16,
shadow::Resolution::_24 => gl::fbo::DepthFormat::_24,
shadow::Resolution::_32 => gl::fbo::DepthFormat::_32,
};
MegaShadowMap::new(gl, atlas_size, format).unwrap()
});
mega_shadow_map
.allocate_shadow_map(parameters)
.map(|map| ShadowMapRef(self.index.insert(map)))
}
pub fn deallocate_shadow_map(&mut self, map: ShadowMapRef){
if let Some(map) = self.index.remove(map.0){
let mega_shadow_map = &mut self.mega_shadow_maps[map.settings.resolution as usize];
mega_shadow_map.reset_occupancy_map();
for (_, map) in self.index.iter_mut() {
let settings = map.settings.clone();
*map = mega_shadow_map.allocate_shadow_map(settings).unwrap();
}
}
}
pub fn fbo(&self, shadow_map_view: &ShadowMapView) -> &glin::Fbo{
let mega_shadow_map = &self.mega_shadow_maps[shadow_map_view.settings.resolution as usize];
&mega_shadow_map.depth_buffers[shadow_map_view.index]
}
pub fn debug_draw_sampler(&self, shadow_map_view: &ShadowMapView) -> glin::TextureSampler{
let mega_shadow_map = &self.mega_shadow_maps[shadow_map_view.settings.resolution as usize];
let fbo = &mega_shadow_map.depth_buffers[shadow_map_view.index];
fbo.depth_tex().unwrap().texture_sampler(&mega_shadow_map.debug_draw_sampler)
}
pub fn shadow_sampler(&self, shadow_map_view: &ShadowMapView) -> glin::TextureSampler{
let mega_shadow_map = &self.mega_shadow_maps[shadow_map_view.settings.resolution as usize];
let fbo = &mega_shadow_map.depth_buffers[shadow_map_view.index];
fbo.depth_tex().unwrap().texture_sampler(&mega_shadow_map.shadow_sampler)
}
pub fn atlas_size(&self) -> u32 {
self.max_texture_size
}
fn update_changed(&mut self, entities: &mut EntitiesThreadLocal){
for (shadow_maps, mut gpu_shadow_maps) in entities.changed_iter_for_mut::<(
Read<shadow::Map>,
Write<Map>)>()
{
for (shadow_map, gpu_shadow_map) in shadow_maps.iter().zip(gpu_shadow_maps.iter_mut()){
let gpu_map = &mut self[gpu_shadow_map.map];
if gpu_map.settings.map_size != shadow_map.parameters().map_size
|| gpu_map.settings.resolution != shadow_map.parameters().resolution
{
self.deallocate_shadow_map(gpu_shadow_map.map);
gpu_shadow_map.map = self
.allocate_shadow_map(shadow_map.parameters().clone())
.unwrap();
gpu_shadow_map.needs_update = true;
}else{
gpu_map.settings = shadow_map.parameters().clone();
}
}
}
for (shadow_maps, mut gpu_shadow_maps) in entities.changed_iter_for_mut::<(
Read<shadow::StaticMap>,
Write<StaticMap>)>()
{
for (shadow_map, gpu_shadow_map) in shadow_maps.iter().zip(gpu_shadow_maps.iter_mut()){
let gpu_map = &mut self[gpu_shadow_map.0];
if gpu_map.settings.map_size != shadow_map.parameters().map_size
|| gpu_map.settings.resolution != shadow_map.parameters().resolution
{
self.deallocate_shadow_map(gpu_shadow_map.0);
gpu_shadow_map.0 = self
.allocate_shadow_map(shadow_map.parameters().clone())
.unwrap();
}else{
gpu_map.settings = shadow_map.parameters().clone();
}
}
}
}
}
impl Index<ShadowMapRef> for ShadowMapPool {
type Output = ShadowMapView;
fn index(&self, shadowref: ShadowMapRef) -> &ShadowMapView{
&self.index[shadowref.0]
}
}
impl IndexMut<ShadowMapRef> for ShadowMapPool {
fn index_mut(&mut self, shadowref: ShadowMapRef) -> &mut ShadowMapView{
&mut self.index[shadowref.0]
}
}
pub trait DepthRenderFn{
fn render_all<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
all_geometry_sorted: &resources::AllShadowsSortedGeometry,
program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
);
fn render_dynamic<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
dynamic_geometry_sorted: &resources::DynamicShadowsSortedGeometry,
program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
);
fn render_static<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
static_geometry_sorted: &resources::StaticShadowsSortedGeometry,
program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
);
}
pub struct BasicRenderer;
impl BasicRenderer {
fn render<'a, 'g, R: glin::RenderSurface, I: Iterator<Item = &'g GpuGeometryRef>>(
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
geometry_sorted: &[resources::ShadowGeometryIndex],
geometryrefs: I,
program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
shadow_geometries: &Sto<'a, ReadOption<'a, ShadowGeometry>>,
material_offsets: Option<&glin::SharedBuffer<u32>>,
model_data_gpu: &gl::SharedBuffer<Mat4>,
)
{
let mut next = 0;
let mut allocators = resources.get_mut::<AllocatorsIndex>().unwrap();
for (geom, geom_index) in shadow_geometries
.iter_for_entities(geometryrefs.map(|g| &**g))
.zip(geometry_sorted.iter())
{
if let Some(geom) = geom {
let num_instances = geom_index.num_instances();
let vao = {
let vao = geom
.full_shadow_vao(&gl, &mut allocators, &model_data_gpu, material_offsets)
.unwrap();
if let Some(material_offsets) = material_offsets {
let material_offset = material_offsets.range(next .. next + num_instances);
vao.set_instance_attribute_buffer_at(
super::AttributeBufferIndex::MaterialOffsets as usize,
material_offset.clone(),
1).unwrap();
}
let model_normal = model_data_gpu.range(next .. next + num_instances);
vao.set_instance_attribute_buffer_at(
super::AttributeBufferIndex::Matrices as usize,
model_normal.clone(),
1).unwrap();
geom.range_vao(&mut allocators, vao)
};
if let Some(materialref) = geom_index.materialref {
let material = &shadow_material_cache[materialref];
let program = &program_cache[material.programref];
let properties = material.alpha_type_properties.iter()
.chain(&material.properties);
let gl_properties = gl.with(properties);
let uniforms = material.all_uniforms();
if num_instances > 1 {
mem::drop(gl_properties.draw_instanced(vao, num_instances, program, uniforms));
}else{
mem::drop(gl_properties.draw(vao, program, uniforms));
}
}else{
if num_instances > 1 {
mem::drop(gl.draw_instanced(vao, num_instances, program, &[]));
}else{
mem::drop(gl.draw(vao, program, &[]));
}
}
next += num_instances;
}
}
}
}
impl DepthRenderFn for BasicRenderer{
fn render_all<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
all_geometry_sorted: &resources::AllShadowsSortedGeometry,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let model_data_gpu = resources.get::<resources::AllModelMatricesBuffer>().unwrap();
let shadow_geometries = entities.storage_for::<ReadOption<ShadowGeometry>>().unwrap();
let material_offsets = resources.get::<ShadowMaterialOffsets>();
Self::render(
resources,
gl,
all_geometry_sorted,
all_geometry_sorted.geometryrefs(),
program_depth_only,
shadow_material_cache,
program_cache,
&shadow_geometries,
material_offsets.as_ref().and_then(|offsets| offsets.all_buffer()),
&model_data_gpu.0
)
}
fn render_dynamic<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
dynamic_geometry_sorted: &resources::DynamicShadowsSortedGeometry,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let model_data_gpu = resources.get::<resources::DynamicModelMatricesBuffer>().unwrap();
let shadow_geometries = entities.storage_for::<ReadOption<ShadowGeometry>>().unwrap();
let material_offsets = resources.get::<ShadowMaterialOffsets>();
Self::render(
resources,
gl,
dynamic_geometry_sorted,
dynamic_geometry_sorted.geometryrefs(),
program_depth_only,
shadow_material_cache,
program_cache,
&shadow_geometries,
material_offsets.as_ref().and_then(|offsets| offsets.dynamic_buffer()),
&model_data_gpu.0
)
}
fn render_static<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
static_geometry_sorted: &resources::StaticShadowsSortedGeometry,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let model_data_gpu = resources.get::<resources::StaticModelMatricesBuffer>().unwrap();
let shadow_geometries = entities.storage_for::<ReadOption<ShadowGeometry>>().unwrap();
let material_offsets = resources.get::<ShadowMaterialOffsets>();
Self::render(
resources,
gl,
static_geometry_sorted,
static_geometry_sorted.geometryrefs(),
program_depth_only,
shadow_material_cache,
program_cache,
&shadow_geometries,
material_offsets.as_ref().and_then(|offsets| offsets.static_buffer()),
&model_data_gpu.0
)
}
}
#[cfg(not(any(feature = "webgl", feature = "gles")))]
pub struct BaseInstanceRenderer;
#[cfg(not(any(feature = "webgl", feature = "gles")))]
impl BaseInstanceRenderer{
fn render<'a, 'g ,R: glin::RenderSurface, I: Iterator<Item = &'g GpuGeometryRef>>(
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
geometry_sorted: &[resources::ShadowGeometryIndex],
geometryrefs: I,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
shadow_geometries: &Sto<'a, ReadOption<'a, ShadowGeometry>>,
material_offsets: Option<&glin::SharedBuffer<u32>>,
model_data_gpu: &gl::SharedBuffer<Mat4>,
)
{
let mut next = 0;
let mut allocators = resources.get_mut::<AllocatorsIndex>().unwrap();
for (geom, geom_index) in shadow_geometries
.iter_for_entities(geometryrefs.map(|g| &**g))
.zip(geometry_sorted.iter())
{
if let Some(geom) = geom {
let num_instances = geom_index.num_instances();
let vao = geom
.shadow_vao_base_instance(&gl, &mut allocators, &model_data_gpu, material_offsets, next as u32)
.unwrap();
if let Some(materialref) = geom_index.materialref {
let material = &shadow_material_cache[materialref];
let program = &program_cache[material.programref];
let properties = material.alpha_type_properties.iter()
.chain(&material.properties);
let gl_properties = gl.with(properties);
let uniforms = material.all_uniforms();
if num_instances > 1 {
mem::drop(gl_properties.draw_instanced(vao, num_instances, program, uniforms));
}else{
mem::drop(gl_properties.draw(vao, program, uniforms));
}
}else{
if num_instances > 1 {
mem::drop(gl.draw_instanced(vao, num_instances, program_depth_only, &[]));
}else{
mem::drop(gl.draw(vao, program_depth_only, &[]));
}
}
next += num_instances;
}
}
}
}
#[cfg(not(any(feature = "webgl", feature = "gles")))]
impl DepthRenderFn for BaseInstanceRenderer{
fn render_all<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
all_geometry_sorted: &resources::AllShadowsSortedGeometry,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let model_data_gpu = resources.get::<resources::AllModelMatricesBuffer>().unwrap();
let mut shadow_geometries = entities.storage_for::<ReadOption<ShadowGeometry>>().unwrap();
let material_offsets = resources.get::<ShadowMaterialOffsets>();
Self::render(
resources,
gl,
all_geometry_sorted,
all_geometry_sorted.geometryrefs(),
program_depth_only,
shadow_material_cache,
program_cache,
&mut shadow_geometries,
material_offsets.as_ref().and_then(|offsets| offsets.all_buffer()),
&model_data_gpu.0
)
}
fn render_dynamic<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
dynamic_geometry_sorted: &resources::DynamicShadowsSortedGeometry,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let model_data_gpu = resources.get::<resources::DynamicModelMatricesBuffer>().unwrap();
let mut shadow_geometries = entities.storage_for::<ReadOption<ShadowGeometry>>().unwrap();
let material_offsets = resources.get::<ShadowMaterialOffsets>();
Self::render(
resources,
gl,
dynamic_geometry_sorted,
dynamic_geometry_sorted.geometryrefs(),
program_depth_only,
shadow_material_cache,
program_cache,
&mut shadow_geometries,
material_offsets.as_ref().and_then(|offsets| offsets.dynamic_buffer()),
&model_data_gpu.0
)
}
fn render_static<'a, R: glin::RenderSurface>(
entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
static_geometry_sorted: &resources::StaticShadowsSortedGeometry,
program_depth_only: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let model_data_gpu = resources.get::<resources::StaticModelMatricesBuffer>().unwrap();
let mut shadow_geometries = entities.storage_for::<ReadOption<ShadowGeometry>>().unwrap();
let material_offsets = resources.get::<ShadowMaterialOffsets>();
Self::render(
resources,
gl,
static_geometry_sorted,
static_geometry_sorted.geometryrefs(),
program_depth_only,
shadow_material_cache,
program_cache,
&mut shadow_geometries,
material_offsets.as_ref().and_then(|offsets| offsets.static_buffer()),
&model_data_gpu.0
)
}
}
#[cfg(not(any(feature = "webgl", feature = "gles")))]
pub struct MultiDrawIndirectRenderer;
#[cfg(not(any(feature = "webgl", feature = "gles")))]
impl MultiDrawIndirectRenderer{
fn render<'a, R: glin::RenderSurface>(
gl: gl::Context<R>,
geometry_sorted: &[resources::ShadowGeometryIndex],
depth_only_program: &gl::Program,
material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
command_buffer: &gl::Buffer<gl::DrawElementsIndirectCommand>,
command_buffer_segments: &[Segment],
)
{
let mut gl_properties = gl.shallow_clone();
let mut prev_material = None;
for segment in command_buffer_segments {
let start = segment.start;
let end = segment.end;
let vao_id = segment.vao_id;
let mode = segment.primitive_type;
let elements = segment.elements;
let commands = command_buffer.range(start .. end);
let geom_index = &geometry_sorted[start];
unsafe{
if let Some(materialref) = geom_index.materialref {
let material = &material_cache[materialref];
let program = &program_cache[material.programref];
if prev_material != geom_index.materialref {
let properties = material.alpha_type_properties.iter()
.chain(&material.properties);
gl_properties = gl.with(properties);
let uniforms = material.all_uniforms();
if elements{
mem::drop(gl_properties.multi_draw_elements_command_vao_id(vao_id, mode, commands, program, uniforms));
}else{
mem::drop(gl_properties.multi_draw_arrays_command_vao_id(vao_id, mode, commands, program, uniforms));
}
}else{
if elements{
mem::drop(gl_properties.multi_draw_elements_command_vao_id(vao_id, mode, commands, program, &[]));
}else{
mem::drop(gl_properties.multi_draw_arrays_command_vao_id(vao_id, mode, commands, program, &[]));
}
};
}else{
if elements{
mem::drop(gl.multi_draw_elements_command_vao_id(vao_id, mode, commands, depth_only_program, &[]));
}else{
mem::drop(gl.multi_draw_arrays_command_vao_id(vao_id, mode, commands, depth_only_program, &[]));
}
}
}
prev_material = geom_index.materialref;
}
}
}
#[cfg(not(any(feature = "webgl", feature = "gles")))]
impl DepthRenderFn for MultiDrawIndirectRenderer{
fn render_all<'a, R: glin::RenderSurface>(
_entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
all_geometry_sorted: &resources::AllShadowsSortedGeometry,
depth_only_program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let command_buffer = resources.get::<AllShadowsCommandBuffer>().unwrap();
let command_buffer_data = resources.get::<AllShadowsCommandBufferData>().unwrap();
Self::render(
gl,
all_geometry_sorted,
depth_only_program,
shadow_material_cache,
program_cache,
&command_buffer.0,
&command_buffer_data.segments,
);
}
fn render_dynamic<'a, R: glin::RenderSurface>(
_entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
dynamic_geometry_sorted: &resources::DynamicShadowsSortedGeometry,
depth_only_program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let command_buffer = resources.get::<ShadowsCommandBuffer>().unwrap();
let command_buffer_data = resources.get::<ShadowsCommandBufferData>().unwrap();
Self::render(
gl,
dynamic_geometry_sorted,
depth_only_program,
shadow_material_cache,
program_cache,
&command_buffer.0,
&command_buffer_data.segments,
);
}
fn render_static<'a, R: glin::RenderSurface>(
_entities: &EntitiesThreadLocal,
resources: &ResourcesThreadLocal,
gl: gl::Context<R>,
static_geometry_sorted: &resources::StaticShadowsSortedGeometry,
depth_only_program: &gl::Program,
shadow_material_cache: &ShadowMaterialCache,
program_cache: &ProgramCache,
)
{
let command_buffer = resources.get::<StaticShadowsCommandBuffer>().unwrap();
let command_buffer_data = resources.get::<StaticShadowsCommandBufferData>().unwrap();
Self::render(
gl,
static_geometry_sorted,
depth_only_program,
shadow_material_cache,
program_cache,
&command_buffer.0,
&command_buffer_data.segments,
);
}
}
pub struct ShadowMapsUpdater<F>{
render: PhantomData<F>,
}
pub fn create_shadow_maps_updater(scene: &mut DeferredScene, renderer_ty: RendererType){
match renderer_ty{
#[cfg(not(any(feature = "webgl", feature = "gles")))]
RendererType::MultiDrawIndirect => {
scene.add_system_thread_local(ShadowMapsUpdater::<MultiDrawIndirectRenderer>{
render: PhantomData,
});
}
#[cfg(not(any(feature = "webgl", feature = "gles")))]
RendererType::BaseInstance => {
scene.add_system_thread_local(ShadowMapsUpdater::<BaseInstanceRenderer>{
render: PhantomData,
});
}
RendererType::Basic => {
scene.add_system_thread_local(ShadowMapsUpdater::<BasicRenderer>{
render: PhantomData,
});
}
}
}
#[system_thread_local(name = "shadow maps update")]
#[needs(
"resources::StaticShadowsSortedGeometry",
"resources::DynamicShadowsSortedGeometry",
"resources::AllShadowsSortedGeometry",
"Node",
"LightAsCameraUBO",
"resources::CameraUBO",
"resources::AllModelMatricesBuffer",
"resources::StaticModelMatricesBuffer",
"resources::DynamicModelMatricesBuffer",
"super::geometry::VertexBuffer",
"shadow::Map",
"shadow::StaticMap",
"AllShadowsCommandBuffer",
"StaticShadowsCommandBuffer",
"ShadowsCommandBuffer",
ShadowMaterialCache,
ProgramCache,
ShadowsCommandBufferData,
StaticShadowsCommandBufferData,
AllShadowsCommandBufferData,
)]
#[updates("Map", "StaticMap", "ShadowMapPool")]
#[reads(Light, gl::Renderer)]
#[writes(
resources::StaticShadowsSortedGeometry,
resources::DynamicShadowsSortedGeometry,
resources::AllShadowsSortedGeometry
)]
#[gpu_stats]
impl<F: DepthRenderFn> SystemThreadLocal for ShadowMapsUpdater<F> {
fn run(&mut self, mut entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
let mut shadow_maps_pool = resources.get_mut::<ShadowMapPool>().unwrap();
shadow_maps_pool.update_changed(&mut entities);
let shadow_material_cache = resources.get::<ShadowMaterialCache>().unwrap();
let program_cache = resources.get::<ProgramCache>().unwrap();
let gl = resources.get::<gl::Renderer<'static>>().unwrap();
#[cfg(gl_debug_groups)]
let _debug_group = gl.new_debug_group(0, "Shadow maps update");
let gl = gl.with_properties(&[
gl::Property::DepthTest(true),
gl::Property::ColorMask([false, false, false, false]),
gl::Property::CullFace(Some(gl::BACK)),
]);
let mut static_geometry_sorted = resources.get_mut::<resources::StaticShadowsSortedGeometry>().unwrap();
let mut dynamic_geometry_sorted = resources.get_mut::<resources::DynamicShadowsSortedGeometry>().unwrap();
let mut all_geometry_sorted = resources.get_mut::<resources::AllShadowsSortedGeometry>().unwrap();
let lights_changed = entities.changed_iter_for::<(Read<Node>, Read<Light>)>()
.next()
.is_some();
let static_changed = entities.changed_iter_for::<Read<shadow::StaticMap>>().next().is_some();
let static_dirty = static_geometry_sorted.has_changed()
|| lights_changed
|| static_changed;
let camera_ubo = resources.get::<resources::CameraUBO>().unwrap();
let lights_maps = entities.iter_for::<(
ReadOption<Map>,
ReadOption<StaticMap>,
Read<LightAsCameraUBO>)>();
for (shadow_map, static_map, light_mvp_ubo) in lights_maps{
let has_static = static_map.map(|maps| !maps.is_empty()).unwrap_or(false);
for ((shadow_map, needs_update, is_static), light_mvp_ubo) in shadow_map.into_iter().flat_map(|s| s)
.map(|s| (&shadow_maps_pool[s.map], s.needs_update, false))
.chain(static_map.into_iter().flat_map(|s| s).map(|s| (&shadow_maps_pool[**s], true, true)))
.zip(light_mvp_ubo)
.sorted_by_key(|((shadow_map, _, _), _)| shadow_map.settings.depth_clamp)
{
#[cfg(not(any(feature="webgl", feature="gles")))]
let program = super::get_depth_only_shader(&gl);
#[cfg(any(feature="webgl", feature="gles"))]
let program = if shadow_map.settings.depth_clamp {
super::get_depth_clamp_shader(&gl)
}else{
super::get_depth_only_shader(&gl)
};
let fbo = shadow_maps_pool.fbo(shadow_map);
let gl = gl.context().with_fbo(fbo);
let shadow_map_viewport = shadow_map.viewport();
#[cfg(not(any(feature="webgl", feature="gles")))]
let gl = gl.with(&[
super::UBOBindingPoints::Camera.to_buffer_binding(&light_mvp_ubo.ubo),
super::UBOBindingPoints::SceneCamera.to_buffer_binding(&camera_ubo.ubo),
gl::Property::DepthClamp(shadow_map.settings.depth_clamp),
gl::Property::Viewport(shadow_map_viewport.into()),
gl::Property::Scissor(Some(shadow_map_viewport.into())),
]);
#[cfg(any(feature="webgl", feature="gles"))]
let gl = gl.with(&[
super::UBOBindingPoints::Camera.to_buffer_binding(&light_mvp_ubo.ubo),
super::UBOBindingPoints::SceneCamera.to_buffer_binding(&camera_ubo.ubo),
gl::Property::Viewport(shadow_map_viewport.into()),
gl::Property::Scissor(Some(shadow_map_viewport.into())),
]);
program.set_uniform(&super::UBOBindingPoints::Camera.to_uniform_block_binding())
.unwrap();
if !is_static && !has_static {
if !needs_update{
continue
}
gl.clear_depth(1.);
F::render_all(
&entities,
&resources,
gl,
&all_geometry_sorted,
program,
&shadow_material_cache,
&program_cache,
);
}else if !is_static && has_static {
if !needs_update{
continue
}
gl.clear_depth(1.);
F::render_dynamic(
&entities,
&resources,
gl,
&dynamic_geometry_sorted,
program,
&shadow_material_cache,
&program_cache,
);
}else if is_static && static_dirty {
log::trace!("Regenerating static shadow map");
gl.clear_depth(1.);
F::render_static(
&entities,
&resources,
gl,
&static_geometry_sorted,
program,
&shadow_material_cache,
&program_cache,
)
}
}
}
all_geometry_sorted.reset_has_changed();
dynamic_geometry_sorted.reset_has_changed();
static_geometry_sorted.reset_has_changed();
}
}