use concinnity_core::gfx::frustum::Frustum;
use concinnity_core::render::spot_shadow;
use windows::Win32::Graphics::Direct3D12::*;
use super::shadow::ShadowView;
use crate::directx::allocator::PooledBuffer;
use crate::directx::com;
use crate::directx::context::DxContext;
use crate::directx::descriptor_slot::SrvSlot;
use crate::directx::texture::GpuResource;
pub(in crate::directx) struct SpotShadowState {
pub resource: Option<GpuResource<ID3D12Resource>>,
pub dsvs: Vec<D3D12_CPU_DESCRIPTOR_HANDLE>,
pub srv_gpu: SrvSlot,
pub buffer: PooledBuffer,
pub ubo: PooledBuffer,
pub ubo_stride: u64,
pub slice_size: u32,
pub frusta: Vec<Frustum>,
pub scheduler: spot_shadow::SpotShadowScheduler,
pub render_mask: u32,
}
impl SpotShadowState {
pub(crate) fn count(&self) -> u32 {
self.dsvs.len() as u32
}
pub(crate) fn advance(&mut self, every_frame: bool) {
let count = self.dsvs.len();
self.render_mask = self.scheduler.next_mask(every_frame, count);
}
pub(crate) fn refreshed_slices(&self) -> impl Iterator<Item = u32> {
spot_shadow::refreshed_slices(self.render_mask, self.count())
}
pub(crate) fn slice_ubo_gva(&self, slice: u32) -> u64 {
debug_assert!(slice < self.count());
let base = com::gpu_va(&self.ubo);
base + slice as u64 * self.ubo_stride
}
}
impl DxContext {
pub(in crate::directx) fn encode_spot_shadow_pass(
&self,
cmd: &ID3D12GraphicsCommandList,
frame_idx: usize,
cam_pos: [f32; 3],
) {
if self.spot_shadow.count() == 0 {
return;
}
self.set_shadow_raster_state(cmd, self.spot_shadow.slice_size);
for slice in self.spot_shadow.refreshed_slices() {
self.clear_shadow_slice(cmd, self.spot_shadow.dsvs[slice as usize]);
}
let Some(indirect) = self.cull.spot_indirect_buffers.get(frame_idx) else {
return;
};
if !self.shadow_views_drawable() {
return;
}
self.encode_spot_culls(cmd, frame_idx, cam_pos);
self.bind_shadow_views(cmd, frame_idx);
for slice in self.spot_shadow.refreshed_slices() {
self.draw_shadow_view(
cmd,
frame_idx,
ShadowView {
dsv: self.spot_shadow.dsvs[slice as usize],
ubo_gva: self.spot_shadow.slice_ubo_gva(slice),
vp_index: 0,
indirect,
first_command: slice as usize * self.cull.bucket_stride,
},
);
}
}
}