use crate::math::{ceilf, get_points_for_ring};
use bitflags::bitflags;
use bytemuck::{Pod, Zeroable};
use core::f32::consts::PI;
use glam::{IVec4, UVec2, Vec2};
const LARGEST_WEIGHT: f32 = 1.0 / (PI * 0.5);
bitflags! {
#[derive(Debug, Clone, Copy, Zeroable, Pod, PartialEq)]
#[repr(C)]
pub struct GlobalFlags: u32 {
const IS_2D = 0b00000001;
const SIMPLE_DISC = 0b00000010;
const HIGH_RESOLUTION_INTERPOLATION = 0b00000100;
const USE_NON_UNIFORM = 0b00001000;
const INVERSE_FOREGROUND_BOKEH_SHAPE = 0b00010000;
const AXIAL_ABERRATION_ENABLE = 0b00100000;
const INVERSE_Y = 0b01000000;
}
#[derive(Debug, Clone, Copy, Zeroable, Pod, PartialEq)]
#[repr(C)]
pub struct NonUniformFlags: u32 {
const CATSEYE_ENABLED = 0b00000001;
const CATSEYE_INVERSE = 0b00000010;
const CATSEYE_INVERSE_FOREGROUND = 0b00000100;
const CATSEYE_SCREEN_RELATIVE = 0b00001000;
const ASTIGMATISM_ENABLED = 0b00010000;
const BARNDOORS_ENABLED = 0b00100000;
const BARNDOORS_INVERSE = 0b01000000;
const BARNDOORS_INVERSE_FOREGROUND = 0b10000000;
}
}
pub struct AxialAberration {
pub enable: bool,
pub amount: f32,
pub color_type: AxialAberrationType,
}
#[repr(u32)]
pub enum AxialAberrationType {
RedBlue = 1,
BlueYellow = 2,
GreenPurple = 3,
}
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
#[repr(C, align(16))]
pub struct ConvolveSettings {
pub process_region: IVec4,
pub full_region: IVec4,
pub resolution: UVec2,
pub filter_resolution: UVec2,
pub center: Vec2,
pub flags: u32,
pub non_uniform_flags: u32,
pub samples: u32,
pub pixel_aspect: f32,
pub size: f32,
pub max_size: f32,
pub catseye_amount: f32,
pub catseye_gamma: f32,
pub catseye_softness: f32,
pub astigmatism_amount: f32,
pub astigmatism_gamma: f32,
pub barndoors_amount: f32,
pub barndoors_gamma: f32,
pub barndoors_top: f32,
pub barndoors_bottom: f32,
pub barndoors_left: f32,
pub barndoors_right: f32,
pub filter_aspect_ratio_normalizer: f32,
pub image_elements: u32,
pub ring_distance: f32,
pub filter_aspect_ratio: f32,
pub pixel_aspect_normalizer: f32,
pub render_scale: u32,
pub axial_aberration_amount: f32,
pub axial_aberration_type: i32,
pub _padding: u32,
}
impl ConvolveSettings {
pub fn compute_sample_weight(&self, coc: f32) -> f32 {
let mut total_points = 1;
let mut ring_id = 0;
let mut remaining_coc = coc;
while remaining_coc > 0.0 {
total_points += get_points_for_ring(ring_id, self.samples, true);
remaining_coc -= self.ring_distance;
ring_id += 1;
}
(1.0 / (total_points as f32)).min(LARGEST_WEIGHT)
}
pub fn get_sample_weights(&self) -> [f32; 2048] {
let mut weights = [0.0; 2048];
for coc in 0..ceilf(self.max_size) as i32 + 1 {
weights[coc as usize] = self.compute_sample_weight(coc as f32)
}
weights
}
pub fn get_image_resolution(&self) -> UVec2 {
UVec2::new(
(self.full_region.z - self.full_region.x) as u32,
(self.full_region.w - self.full_region.y) as u32,
)
}
pub fn get_real_coordinates(&self, coordinates: UVec2) -> UVec2 {
UVec2::new(
(self.full_region.x as u32) + coordinates.x,
(self.full_region.y as u32) + coordinates.y,
)
}
pub fn get_axial_aberration_settings(&self) -> AxialAberration {
AxialAberration {
enable: NonUniformFlags::from_bits_retain(self.non_uniform_flags)
.contains(NonUniformFlags::BARNDOORS_ENABLED),
amount: self.axial_aberration_amount,
color_type: match self.axial_aberration_type {
1 => AxialAberrationType::RedBlue,
2 => AxialAberrationType::BlueYellow,
3 => AxialAberrationType::GreenPurple,
_ => AxialAberrationType::RedBlue,
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_struct_size() {
assert_eq!(core::mem::size_of::<ConvolveSettings>(), 160)
}
}