opendefocus_datastructure/
lib.rs1#![warn(unused_extern_crates)]
2
3use circle_of_confusion::Math;
4use glam::{IVec4, UVec2, Vec2};
5use opendefocus_shared::{ConvolveSettings, GlobalFlags, NonUniformFlags};
6
7use opendefocus_shared::math::{ceilf, floorf};
8
9use crate::defocus::DefocusMode;
10use crate::render::{FilterMode, Quality};
11
12include!(concat!(env!("OUT_DIR"), "/opendefocus.rs"));
13
14impl IVector4 {
15 pub fn to_ivec4(&self) -> IVec4 {
16 IVec4::new(self.x, self.y, self.z, self.w)
17 }
18}
19
20impl UVector2 {
21 pub fn to_uvec2(&self) -> UVec2 {
22 UVec2::new(self.x, self.y)
23 }
24}
25
26impl Vector2 {
27 pub fn to_vec2(&self) -> Vec2 {
28 Vec2::new(self.x, self.y)
29 }
30}
31
32impl render::Filter {
33 pub fn calculate_filter_box(&self, aspect_ratio: f32) -> [u32; 4] {
34 let resolution = UVector2 {
35 x: self.resolution,
36 y: self.resolution,
37 };
38 let offset_multiplier = Vector2 {
39 x: 3.0 - aspect_ratio.min(1.0) * 2.0,
40 y: aspect_ratio.max(1.0) * 2.0 - 1.0,
41 };
42 let offset = UVector2 {
43 x: floorf((resolution.x as f32 / offset_multiplier.x) * (1.0 - aspect_ratio).max(0.0))
44 as u32,
45 y: floorf((resolution.y as f32 / offset_multiplier.y) * (aspect_ratio - 1.0).max(0.0))
46 as u32,
47 };
48 [
49 offset.x,
50 offset.y,
51 resolution.x - offset.x,
52 resolution.y - offset.y,
53 ]
54 }
55}
56
57impl render::RenderSpecs {
58 pub fn from_rects(full_region: IVec4, render_region: IVec4) -> Self {
60 Self {
61 full_region: IVector4 {
62 x: full_region.x,
63 y: full_region.y,
64 z: full_region.z,
65 w: full_region.w,
66 },
67 render_region: IVector4 {
68 x: render_region.x,
69 y: render_region.y,
70 z: render_region.z,
71 w: render_region.w,
72 },
73 }
74 }
75
76 pub fn scale(&self, scale: f32) -> Self {
78 let mut scaled_full_region = self.full_region;
79 scaled_full_region.x = floorf(scaled_full_region.x as f32 * scale) as i32;
80 scaled_full_region.y = floorf(scaled_full_region.y as f32 * scale) as i32;
81 scaled_full_region.z = ceilf(scaled_full_region.z as f32 * scale) as i32;
82 scaled_full_region.w = ceilf(scaled_full_region.w as f32 * scale) as i32;
83
84 let mut scaled_render_region = self.render_region;
85 scaled_render_region.x = floorf(scaled_render_region.x as f32 * scale) as i32;
86 scaled_render_region.y = floorf(scaled_render_region.y as f32 * scale) as i32;
87 scaled_render_region.z = ceilf(scaled_render_region.z as f32 * scale) as i32;
88 scaled_render_region.w = ceilf(scaled_render_region.w as f32 * scale) as i32;
89 Self {
90 full_region: scaled_full_region,
91 render_region: scaled_render_region,
92 }
93 }
94
95 pub fn get_resolution(&self) -> UVec2 {
97 UVec2::new(
98 (self.full_region.z - self.full_region.x) as u32,
99 (self.full_region.w - self.full_region.y) as u32,
100 )
101 }
102
103 pub fn get_render_resolution(&self) -> UVec2 {
105 UVec2::new(
106 (self.render_region.z - self.render_region.x) as u32,
107 (self.render_region.w - self.render_region.y) as u32,
108 )
109 }
110}
111
112impl defocus::Settings {
113 pub fn get_size(&self) -> f32 {
115 self.circle_of_confusion.size
116 * self.circle_of_confusion.pixel_aspect
117 * self.size_multiplier.max(0.0)
118 * self.proxy_scale.unwrap_or(1.0)
119 }
120
121 pub fn get_raw_max_size(&self) -> f32 {
122 match self.circle_of_confusion.camera_data {
123 Some(_) => self.camera_max_size,
124 _ => self.circle_of_confusion.max_size,
125 }
126 }
127
128 fn get_size_multiplier(&self) -> f32 {
129 self.size_multiplier.max(0.0)
130 }
131
132 fn get_proxy_scale(&self) -> f32 {
133 self.proxy_scale.unwrap_or(1.0)
134 }
135
136 pub fn get_max_size(&self) -> f32 {
138 let max_size = self.get_raw_max_size();
139 max_size
140 * self.circle_of_confusion.pixel_aspect
141 * self.get_size_multiplier()
142 * self.get_proxy_scale()
143 }
144
145 pub fn get_math(&self) -> Math {
147 todo!()
148 }
149
150 pub fn get_current_max_size(&self) -> f32 {
152 if self.defocus_mode() == DefocusMode::Twod {
153 return self.get_size();
154 }
155 self.get_max_size()
156 }
157
158 pub fn get_padding(&self) -> u32 {
160 (ceilf(self.get_current_max_size())) as u32
161 }
162}
163
164impl render::Settings {
165 pub fn get_quality(&self) -> Quality {
166 if self.gui {
167 self.quality()
168 } else {
169 self.farm_quality()
170 }
171 }
172}
173
174fn settings_to_globalflags(settings: &Settings, non_uniform_flags: NonUniformFlags) -> GlobalFlags {
175 let mut flags = GlobalFlags::empty();
176 if settings.render.filter.mode() == FilterMode::Simple {
177 flags |= GlobalFlags::SIMPLE_DISC;
178 }
179 if non_uniform_flags.intersects(
180 NonUniformFlags::CATSEYE_ENABLED
181 | NonUniformFlags::BARNDOORS_ENABLED
182 | NonUniformFlags::ASTIGMATISM_ENABLED,
183 ) {
184 flags |= GlobalFlags::USE_NON_UNIFORM;
185 }
186
187 if settings.defocus.defocus_mode() == DefocusMode::Twod {
188 flags |= GlobalFlags::IS_2D;
189 }
190 if settings.non_uniform.inverse_foreground {
191 flags |= GlobalFlags::INVERSE_FOREGROUND_BOKEH_SHAPE;
192 }
193 if settings.render.inverse_y {
194 flags |= GlobalFlags::INVERSE_Y;
195 }
196 if settings.non_uniform.axial_aberration.enable {
197 flags |= GlobalFlags::AXIAL_ABERRATION_ENABLE;
198 }
199 flags
200}
201
202fn non_uniform_to_flags(settings: &non_uniform::Settings) -> NonUniformFlags {
203 let mut non_uniform_flags = NonUniformFlags::empty();
204 if settings.catseye.enable {
205 non_uniform_flags |= NonUniformFlags::CATSEYE_ENABLED;
206 if settings.catseye.inverse {
207 non_uniform_flags |= NonUniformFlags::CATSEYE_INVERSE;
208 }
209 if settings.catseye.inverse_foreground {
210 non_uniform_flags |= NonUniformFlags::CATSEYE_INVERSE_FOREGROUND;
211 }
212 if settings.catseye.relative_to_screen {
213 non_uniform_flags |= NonUniformFlags::CATSEYE_SCREEN_RELATIVE;
214 }
215 }
216
217 if settings.astigmatism.enable {
218 non_uniform_flags |= NonUniformFlags::ASTIGMATISM_ENABLED;
219 }
220
221 if settings.barndoors.enable {
222 non_uniform_flags |= NonUniformFlags::BARNDOORS_ENABLED;
223 if settings.barndoors.inverse {
224 non_uniform_flags |= NonUniformFlags::BARNDOORS_INVERSE
225 }
226 if settings.barndoors.inverse_foreground {
227 non_uniform_flags |= NonUniformFlags::BARNDOORS_INVERSE_FOREGROUND
228 }
229 }
230 non_uniform_flags
231}
232
233pub fn get_samples(settings: &render::Settings, size: i32) -> u32 {
244 let quality = settings.get_quality();
245 match quality {
246 render::Quality::Low => (size as f32 * 0.1).clamp(8.0, 20.0) as u32,
247 render::Quality::Medium => (size as f32 * 0.2).clamp(12.0, 50.0) as u32,
248 render::Quality::High => (size as f32 * 0.5).clamp(30.0, 100.0) as u32,
249 render::Quality::Custom => settings.samples as u32,
250 }
251}
252
253pub fn settings_to_convolve_settings(
254 settings: &Settings,
255 render_specs: &render::RenderSpecs,
256 filter_resolution: UVec2,
257 image_elements: u32,
258) -> ConvolveSettings {
259 let max_size = if settings.defocus.defocus_mode() == DefocusMode::Twod {
260 settings.defocus.get_size()
261 } else {
262 settings.defocus.get_raw_max_size()
263 };
264 let samples = get_samples(&settings.render, ceilf(max_size) as i32);
265 let filter_aspect_ratio = filter_resolution.x as f32 / filter_resolution.y as f32;
266 let filter_aspect_ratio_normalizer = 1.0 / filter_aspect_ratio;
267 let ring_distance = max_size / samples as f32;
268 let pixel_aspect_normalizer = 1.0 / settings.defocus.circle_of_confusion.pixel_aspect;
269
270 let non_uniform_flags = non_uniform_to_flags(&settings.non_uniform);
271 let flags = settings_to_globalflags(settings, non_uniform_flags);
272
273 ConvolveSettings {
274 samples,
275 center: settings.render.center.to_vec2(),
276 process_region: render_specs.render_region.to_ivec4(),
277 full_region: render_specs.full_region.to_ivec4(),
278 resolution: settings.render.resolution.to_uvec2(),
279 pixel_aspect: settings.defocus.circle_of_confusion.pixel_aspect,
280 size: settings.defocus.get_size(),
281 max_size,
282 flags: flags.bits(),
283 non_uniform_flags: non_uniform_flags.bits(),
284 catseye_amount: settings.non_uniform.catseye.amount,
285 catseye_gamma: settings.non_uniform.catseye.gamma,
286 catseye_softness: settings.non_uniform.catseye.softness,
287 astigmatism_amount: settings.non_uniform.astigmatism.amount,
288 astigmatism_gamma: settings.non_uniform.astigmatism.gamma,
289 barndoors_amount: settings.non_uniform.barndoors.amount,
290 barndoors_gamma: settings.non_uniform.barndoors.gamma,
291 barndoors_top: settings.non_uniform.barndoors.top,
292 barndoors_bottom: settings.non_uniform.barndoors.bottom,
293 barndoors_left: settings.non_uniform.barndoors.left,
294 barndoors_right: settings.non_uniform.barndoors.right,
295 axial_aberration_amount: settings.non_uniform.axial_aberration.amount,
296 axial_aberration_type: settings.non_uniform.axial_aberration.color_type,
297 filter_aspect_ratio_normalizer,
298 filter_aspect_ratio,
299 ring_distance,
300 filter_resolution,
301 pixel_aspect_normalizer,
302 render_scale: 1 as u32,
303 image_elements,
304 _padding: 0,
305 }
306}