use concinnity_core::render::depth::{
DEPTH_CLEAR, DEPTH_INCLUSIVE_COMPARE, DEPTH_WRITE_COMPARE, DepthCompare,
};
use concinnity_core::render::error::{RenderError, RenderResult};
use objc2::rc::Retained;
use objc2::runtime::ProtocolObject;
use objc2_metal::{MTLCompareFunction, MTLDepthStencilDescriptor, MTLDepthStencilState, MTLDevice};
#[derive(Clone, Copy, Debug)]
pub(in crate::metal) struct Depth {
compare: DepthCompare,
write: bool,
}
impl Depth {
pub(in crate::metal) const fn write() -> Self {
Self {
compare: DEPTH_WRITE_COMPARE,
write: true,
}
}
pub(in crate::metal) const fn write_inclusive() -> Self {
Self {
compare: DEPTH_INCLUSIVE_COMPARE,
write: true,
}
}
pub(in crate::metal) const fn read_only() -> Self {
Self {
compare: DEPTH_INCLUSIVE_COMPARE,
write: false,
}
}
pub(in crate::metal) fn state(
self,
device: &ProtocolObject<dyn MTLDevice>,
) -> RenderResult<Retained<ProtocolObject<dyn MTLDepthStencilState>>> {
let desc = MTLDepthStencilDescriptor::new();
desc.setDepthCompareFunction(compare_function(self.compare));
desc.setDepthWriteEnabled(self.write);
device
.newDepthStencilStateWithDescriptor(&desc)
.ok_or_else(|| RenderError::Other("failed to create depth stencil state".into()))
}
}
const fn compare_function(compare: DepthCompare) -> MTLCompareFunction {
match compare {
DepthCompare::Less => MTLCompareFunction::Less,
DepthCompare::LessEqual => MTLCompareFunction::LessEqual,
DepthCompare::Greater => MTLCompareFunction::Greater,
DepthCompare::GreaterEqual => MTLCompareFunction::GreaterEqual,
}
}
pub(in crate::metal) const CLEAR_DEPTH: f64 = DEPTH_CLEAR as f64;
pub(in crate::metal) const SHADOW_SAMPLE_COMPARE: MTLCompareFunction =
compare_function(DEPTH_INCLUSIVE_COMPARE);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_compare_maps_to_its_metal_function() {
assert_eq!(
compare_function(DepthCompare::Less),
MTLCompareFunction::Less
);
assert_eq!(
compare_function(DepthCompare::LessEqual),
MTLCompareFunction::LessEqual
);
assert_eq!(
compare_function(DepthCompare::Greater),
MTLCompareFunction::Greater
);
assert_eq!(
compare_function(DepthCompare::GreaterEqual),
MTLCompareFunction::GreaterEqual
);
}
#[test]
fn the_shadow_sampler_passes_at_or_nearer_the_light() {
assert_eq!(SHADOW_SAMPLE_COMPARE, MTLCompareFunction::GreaterEqual);
assert_eq!(CLEAR_DEPTH, 0.0);
}
}