Skip to main content

opendefocus_shared/
internal_settings.rs

1use crate::math::{ceilf, get_points_for_ring};
2
3use bitflags::bitflags;
4use bytemuck::{Pod, Zeroable};
5use core::f32::consts::PI;
6use glam::{IVec4, UVec2, Vec2};
7const LARGEST_WEIGHT: f32 = 1.0 / (PI * 0.5);
8
9bitflags! {
10    /// These are the most commonly used flags, to reduce memory reads they are together
11    #[derive(Debug, Clone, Copy, Zeroable, Pod, PartialEq)]
12    #[repr(C)]
13    pub struct GlobalFlags: u32 {
14        /// Processing in 2d or using depth map
15        const IS_2D                                         = 0b00000001;
16        /// Use a simple disc, this prevents reads to the filter kernel
17        const SIMPLE_DISC                                   = 0b00000010;
18        /// Merge low defocus size over the original image
19        const HIGH_RESOLUTION_INTERPOLATION                 = 0b00000100;
20        /// Use non uniform bokeh calculations
21        const USE_NON_UNIFORM                               = 0b00001000;
22        /// Inverse the bokeh shape in the foreground
23        const INVERSE_FOREGROUND_BOKEH_SHAPE                = 0b00010000;
24        /// Enable offset size of the filter kernel per channel
25        const AXIAL_ABERRATION_ENABLE                       = 0b00100000;
26        /// Interpret the y from bottom to top
27        const INVERSE_Y                                     = 0b01000000;
28
29    }
30
31    // Flags for non uniform settings
32    #[derive(Debug, Clone, Copy, Zeroable, Pod, PartialEq)]
33    #[repr(C)]
34    pub struct NonUniformFlags: u32 {
35        /// Use Catseye non uniform calculations
36        const CATSEYE_ENABLED                               = 0b00000001;
37        /// Flag indicating whether to invert catseye for foreground
38        const CATSEYE_INVERSE                               = 0b00000010;
39        /// Flag indicating whether to invert catseye for foreground
40        const CATSEYE_INVERSE_FOREGROUND                    = 0b00000100;
41        /// Flag indicating whether catseye is screen relative
42        const CATSEYE_SCREEN_RELATIVE                       = 0b00001000;
43        /// Enable the astigmatism artifact
44        const ASTIGMATISM_ENABLED                           = 0b00010000;
45        /// Enable the barndoors cutting of bokehs
46        const BARNDOORS_ENABLED                             = 0b00100000;
47        /// Inverse the entirity of barndoors
48        const BARNDOORS_INVERSE                             = 0b01000000;
49        /// Inverse barndoors only in foreground
50        const BARNDOORS_INVERSE_FOREGROUND                  = 0b10000000;
51    }
52
53}
54
55/// Artifact that is caused by the light rays entering the lens at a different
56/// rate at different focal distances.
57pub struct AxialAberration {
58    /// Flag indicating whether axial aberration is enabled
59    pub enable: bool,
60    /// Amount of the axial aberration effect
61    pub amount: f32,
62    /// Color type for the aberration
63    pub color_type: AxialAberrationType,
64}
65
66#[repr(u32)]
67pub enum AxialAberrationType {
68    /// Red and blue color combination
69    RedBlue = 1,
70    /// Blue and yellow color combination
71    BlueYellow = 2,
72    /// Green and purple color combination
73    GreenPurple = 3,
74}
75
76/// Settings structure for convolution operations.
77#[derive(Copy, Clone, Debug, Pod, Zeroable)]
78#[repr(C, align(16))]
79pub struct ConvolveSettings {
80    /// Region to process (x, y, width, height)
81    pub process_region: IVec4,
82    /// Full region (x, y, width, height)
83    pub full_region: IVec4,
84    /// Resolution of the render (width, height)
85    pub resolution: UVec2,
86    /// Resolution of the filter (width, height)
87    pub filter_resolution: UVec2,
88    /// Center point of the convolution
89    pub center: Vec2,
90    /// Global operation flags
91    pub flags: u32,
92    /// Flags for non uniform settings
93    pub non_uniform_flags: u32,
94    /// Number of samples to use for convolution
95    pub samples: u32,
96    /// Pixel aspect ratio
97    pub pixel_aspect: f32,
98    /// Base size for convolution
99    pub size: f32,
100    /// Maximum size for convolution
101    pub max_size: f32,
102    /// Amount of catseye effect
103    pub catseye_amount: f32,
104    /// Gamma correction for catseye
105    pub catseye_gamma: f32,
106    /// Softness of catseye edges
107    pub catseye_softness: f32,
108    /// Amount of astigmatism
109    pub astigmatism_amount: f32,
110    /// Gamma correction for astigmatism
111    pub astigmatism_gamma: f32,
112    /// Amount of barndoors effect
113    pub barndoors_amount: f32,
114    /// Gamma correction for barndoors
115    pub barndoors_gamma: f32,
116    /// Top position of barndoors
117    pub barndoors_top: f32,
118    /// Bottom position of barndoors
119    pub barndoors_bottom: f32,
120    /// Left position of barndoors
121    pub barndoors_left: f32,
122    /// Right position of barndoors
123    pub barndoors_right: f32,
124    /// Normalization factor for filter aspect ratio
125    pub filter_aspect_ratio_normalizer: f32,
126    /// Total number of
127    pub image_elements: u32,
128    /// Distance between rings in the filter
129    pub ring_distance: f32,
130    /// Aspect ratio of the filter
131    pub filter_aspect_ratio: f32,
132    /// Normalization factor for pixel aspect
133    pub pixel_aspect_normalizer: f32,
134    /// Size of render
135    pub render_scale: u32,
136    /// Flag indicating whether to invert foreground bokeh shape
137    pub axial_aberration_amount: f32,
138    pub axial_aberration_type: i32,
139
140    pub _padding: u32,
141}
142impl ConvolveSettings {
143    pub fn compute_sample_weight(&self, coc: f32) -> f32 {
144        let mut total_points = 1;
145        let mut ring_id = 0;
146        let mut remaining_coc = coc;
147
148        while remaining_coc > 0.0 {
149            total_points += get_points_for_ring(ring_id, self.samples, true);
150            remaining_coc -= self.ring_distance;
151            ring_id += 1;
152        }
153        (1.0 / (total_points as f32)).min(LARGEST_WEIGHT)
154    }
155
156    pub fn get_sample_weights(&self) -> [f32; 2048] {
157        let mut weights = [0.0; 2048];
158        for coc in 0..ceilf(self.max_size) as i32 + 1 {
159            weights[coc as usize] = self.compute_sample_weight(coc as f32)
160        }
161        weights
162    }
163
164    pub fn get_image_resolution(&self) -> UVec2 {
165        UVec2::new(
166            (self.full_region.z - self.full_region.x) as u32,
167            (self.full_region.w - self.full_region.y) as u32,
168        )
169    }
170
171    /// Get the coordinates in screen-space based on the full region
172    pub fn get_real_coordinates(&self, coordinates: UVec2) -> UVec2 {
173        UVec2::new(
174            (self.full_region.x as u32) + coordinates.x,
175            (self.full_region.y as u32) + coordinates.y,
176        )
177    }
178
179    pub fn get_axial_aberration_settings(&self) -> AxialAberration {
180        AxialAberration {
181            enable: NonUniformFlags::from_bits_retain(self.non_uniform_flags)
182                .contains(NonUniformFlags::BARNDOORS_ENABLED),
183            amount: self.axial_aberration_amount,
184            color_type: match self.axial_aberration_type {
185                1 => AxialAberrationType::RedBlue,
186                2 => AxialAberrationType::BlueYellow,
187                3 => AxialAberrationType::GreenPurple,
188                _ => AxialAberrationType::RedBlue,
189            },
190        }
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    /// Struct size needs to be properly aligned for spirv
199    #[test]
200    fn test_struct_size() {
201        assert_eq!(core::mem::size_of::<ConvolveSettings>(), 160)
202    }
203}