use rin::gl::{self, CreationContext};
use generational_arena::{self as arena, Arena};
use std::ops::{Index, IndexMut};
use rinecs::{EntitiesThreadLocal, ResourcesThreadLocal, Read, ReadOption};
use super::resources;
use crate::light::Light;
use super::light::LightMatricesUBO;
use super::geometry::{
ShadowGeometry, StaticShadowGeometry, AllShadowGeometry,
};
#[cfg(feature="gl_multidraw_indirect")]
use super::geometry::{
AllShadowsCommandBuffer, AllShadowsCommandBufferData,
StaticShadowsCommandBuffer, StaticShadowsCommandBufferData,
ShadowsCommandBuffer, ShadowsCommandBufferData,
};
use crate::transformation::Transformation;
#[derive(Component, Debug)]
#[debug_as_string]
pub struct Map(pub(crate) ShadowMapRef);
#[derive(Component, Debug)]
#[debug_as_string]
pub struct StaticMap(pub(crate) ShadowMapRef);
pub struct ShadowMapPool{
creation_proxy: gl::CreationProxy,
shadow_maps: Arena<gl::GenericShadowMap>
}
impl ShadowMapPool{
pub fn new(proxy: gl::CreationProxy) -> ShadowMapPool {
ShadowMapPool{
shadow_maps: Arena::new(),
creation_proxy: proxy,
}
}
pub fn new_shadow_map(&mut self, settings: gl::shadow_mapping::Settings, resolution: glin::fbo::DepthFormat) -> glin::Result<ShadowMapRef>{
self.creation_proxy
.new_shadow_map()
.create_generic(settings, resolution)
.map(|shadow_map| ShadowMapRef(self.shadow_maps.insert(shadow_map)))
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ShadowMapRef(arena::Index);
impl Index<ShadowMapRef> for ShadowMapPool{
type Output = gl::GenericShadowMap;
fn index(&self, shadowref: ShadowMapRef) -> &gl::GenericShadowMap{
&self.shadow_maps[shadowref.0]
}
}
impl IndexMut<ShadowMapRef> for ShadowMapPool{
fn index_mut(&mut self, shadowref: ShadowMapRef) -> &mut gl::GenericShadowMap{
&mut self.shadow_maps[shadowref.0]
}
}
pub fn shadow_maps_updater(entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
let gl = resources.get::<gl::Renderer<'static>>().unwrap();
let gl = gl.with_properties(&[
gl::Property::DepthTest(true),
gl::Property::ColorMask([false, false, false, false]),
]);
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.iter_for::<(Read<Transformation>, Read<Light>)>()
.any(|(t,_)| t.has_changed());
let static_dirty = static_geometry_sorted.has_changed() || lights_changed;
let shadow_maps_pool = resources.get::<ShadowMapPool>().unwrap();
let lights_maps = entities.iter_for::<(
ReadOption<Map>,
ReadOption<StaticMap>,
Read<LightMatricesUBO>)>();
for (shadow_map, static_map, light_mvp_ubo) in lights_maps{
let has_static = static_map.is_some();
for ((shadow_map, is_static), light_mvp_ubo) in shadow_map.map(|s| (&shadow_maps_pool[**s], false)).into_iter()
.chain(static_map.into_iter().filter_map(|s| if static_dirty{
Some((&shadow_maps_pool[**s], true))
}else{
None
}))
.zip(light_mvp_ubo)
{
let program = super::get_depth_only_shader(&gl);
let gl = gl.context().with_fbo(shadow_map.fbo());
let gl = gl.with(&[gl::UBOBindingPoints::Camera.to_buffer_binding(&light_mvp_ubo.ubo)]);
program.set_uniform(&gl::UBOBindingPoints::Camera.to_uniform_block_binding())
.unwrap();
if !is_static && !has_static {
let model_data_gpu = resources.get::<resources::AllModelMatricesBuffer>().unwrap();
gl.clear_depth();
#[cfg(not(feature="gl_multidraw_indirect"))]
{
let mut next = 0;
for (geom, geom_index) in entities
.iter_for_entities::<Read<AllShadowGeometry>, _>(all_geometry_sorted.geometryrefs().map(|g| *g))
.zip(all_geometry_sorted.iter())
{
let num_instances = geom_index.num_instances();
#[cfg(not(feature="gl_base_instance"))]
let vao = {
let vao = geom
.full_shadow_vao(&gl, &resources, &model_data_gpu)
.unwrap();
let model_normal = model_data_gpu.range(next .. next + num_instances);
vao.set_instance_attribute_buffer_at(5, model_normal, 1).unwrap();
geom.range_vao(&resources, vao)
};
#[cfg(feature="gl_base_instance")]
let vao = geom
.shadow_vao_base_instance(&gl, &resources, &model_data_gpu, next as u32)
.unwrap();
if num_instances > 1 {
gl.draw_instanced(vao, num_instances, program, &[])
.is_ok();
}else{
gl.draw(vao, program, &[])
.is_ok();
}
next += num_instances;
}
}
#[cfg(feature="gl_multidraw_indirect")]
{
let command_buffer = resources.get::<AllShadowsCommandBuffer>().unwrap();
let command_buffer_data = resources.get::<AllShadowsCommandBufferData>().unwrap();
for segment in command_buffer_data.segments.windows(2){
let start = segment[0];
let end = segment[1];
let commands = command_buffer.0.range(start .. end);
let geom_index = &all_geometry_sorted[start];
let geom = entities.component_for::<AllShadowGeometry>(&geom_index.geometryref)
.unwrap();
let vao = geom
.full_shadow_vao(&gl, &resources, &model_data_gpu)
.unwrap();
let vao = vao.full_range(geom.primitive_type());
if geom.has_indices(){
gl.multi_draw_elements_command(vao, commands, program, &[])
.is_ok();
}else{
gl.multi_draw_arrays_command(vao, commands, program, &[])
.is_ok();
}
}
}
}else if !is_static && has_static {
let model_data_gpu = resources.get::<resources::DynamicModelMatricesBuffer>().unwrap();
gl.clear_depth();
#[cfg(not(feature="gl_multidraw_indirect"))]
{
let mut next = 0;
for (geom, geom_index) in entities
.iter_for_entities::<Read<ShadowGeometry>, _>(dynamic_geometry_sorted.geometryrefs().map(|g| *g))
.zip(dynamic_geometry_sorted.iter())
{
let num_instances = geom_index.num_instances();
#[cfg(not(feature="gl_base_instance"))]
let vao = {
let vao = geom
.full_shadow_vao(&gl, &resources, &model_data_gpu)
.unwrap();
let model_normal = model_data_gpu.range(next .. next + num_instances);
vao.set_instance_attribute_buffer_at(5, model_normal, 1).unwrap();
geom.range_vao(&resources, vao)
};
#[cfg(feature="gl_base_instance")]
let vao = geom
.shadow_vao_base_instance(&gl, &resources, &model_data_gpu, next as u32)
.unwrap();
if num_instances > 1 {
gl.draw_instanced(vao, num_instances, program, &[])
.is_ok();
}else{
gl.draw(vao, program, &[])
.is_ok();
}
next += num_instances;
}
}
#[cfg(feature="gl_multidraw_indirect")]
{
let command_buffer = resources.get::<ShadowsCommandBuffer>().unwrap();
let command_buffer_data = resources.get::<ShadowsCommandBufferData>().unwrap();
for segment in command_buffer_data.segments.windows(2){
let start = segment[0];
let end = segment[1];
let commands = command_buffer.0.range(start .. end);
let geom_index = &dynamic_geometry_sorted[start];
let geom = entities.component_for::<ShadowGeometry>(&geom_index.geometryref)
.unwrap();
let vao = geom
.full_shadow_vao(&gl, &resources, &model_data_gpu)
.unwrap();
let vao = vao.full_range(geom.primitive_type());
if geom.has_indices(){
gl.multi_draw_elements_command(vao, commands, program, &[])
.is_ok();
}else{
gl.multi_draw_arrays_command(vao, commands, program, &[])
.is_ok();
}
}
}
}else if is_static && static_dirty{
trace!("Regenerating static shadow map");
let model_data_gpu = resources.get::<resources::StaticModelMatricesBuffer>().unwrap();
gl.clear_depth();
#[cfg(not(feature="gl_multidraw_indirect"))]
{
let mut next = 0;
for (geom, geom_index) in entities
.iter_for_entities::<Read<StaticShadowGeometry>, _>(static_geometry_sorted.geometryrefs().map(|g| *g))
.zip(static_geometry_sorted.iter())
{
let num_instances = geom_index.num_instances();
#[cfg(not(feature="gl_base_instance"))]
let vao = {
let vao = geom
.full_shadow_vao(&gl, &resources, &model_data_gpu)
.unwrap();
let model_normal = model_data_gpu.range(next .. next + num_instances);
vao.set_instance_attribute_buffer_at(5, model_normal, 1).unwrap();
geom.range_vao(&resources, vao)
};
#[cfg(feature="gl_base_instance")]
let vao = geom
.shadow_vao_base_instance(&gl, &resources, &model_data_gpu, next as u32)
.unwrap();
if num_instances > 1 {
gl.draw_instanced(vao, num_instances, program, &[])
.is_ok();
}else{
gl.draw(vao, program, &[])
.is_ok();
}
next += num_instances;
}
}
#[cfg(feature="gl_multidraw_indirect")]
{
let command_buffer = resources.get::<StaticShadowsCommandBuffer>().unwrap();
let command_buffer_data = resources.get::<StaticShadowsCommandBufferData>().unwrap();
for segment in command_buffer_data.segments.windows(2){
let start = segment[0];
let end = segment[1];
let commands = command_buffer.0.range(start .. end);
let geom_index = &static_geometry_sorted[start];
let geom = entities.component_for::<StaticShadowGeometry>(&geom_index.geometryref)
.unwrap();
let vao = geom
.full_shadow_vao(&gl, &resources, &model_data_gpu)
.unwrap();
let vao = vao.full_range(geom.primitive_type());
if geom.has_indices(){
gl.multi_draw_elements_command(vao, commands, program, &[])
.is_ok();
}else{
gl.multi_draw_arrays_command(vao, commands, program, &[])
.is_ok();
}
}
}
}
}
}
all_geometry_sorted.reset_has_changed();
dynamic_geometry_sorted.reset_has_changed();
static_geometry_sorted.reset_has_changed();
}