1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
use rayon::prelude::*;
use crate::{
camera::Camera,
error::TracerError,
image::SubImage,
renderer::{cpu::CpuRenderer, do_cancel, ray_color, Renderer},
util::random_double,
vec3::Vec3,
};
use super::RenderData;
fn get_highest_divdable(value: usize, mut div: usize) -> usize {
// Feels like there could possibly be some other nicer trick to this.
while (value % div) != 0 {
div -= 1;
}
div
}
pub struct CpuRendererScaled {}
impl CpuRendererScaled {
pub fn raytrace(
&self,
rd: &RenderData,
camera: &Camera,
image: &SubImage,
scale: (usize, usize),
) -> Result<(), TracerError> {
let (scale_width, scale_height) = scale;
let scaled_width = image.width / scale_width;
let scaled_height = image.height / scale_height;
let mut colors: Vec<Vec3> = vec![Vec3::default(); scaled_height * scaled_width];
for row in 0..scaled_height {
for column in 0..scaled_width {
let u: f64 = ((image.x + column * scale_width) as f64 + random_double())
/ (image.screen_width - 1) as f64;
for _ in 0..rd.config.preview.samples {
let v: f64 = ((image.y + row * scale_height) as f64 + random_double())
/ (image.screen_height - 1) as f64;
colors[row * scaled_width + column].add(ray_color(
rd.scene,
&camera.get_ray(u, v),
rd.config.preview.max_depth,
));
}
}
if do_cancel(rd.cancel_event) {
return Ok(());
}
}
(!do_cancel(rd.cancel_event))
.then_some(|| ())
.ok_or(TracerError::CancelEvent)
.and_then(|_| {
rd.buffer
.write()
.map_err(|e| TracerError::FailedToAcquireLock(e.to_string()))
})
.map(|mut buf| {
let offset = image.y * image.screen_width + image.x;
for scaled_row in 0..scaled_height {
for scaled_col in 0..scaled_width {
let color = colors[scaled_row * scaled_width + scaled_col]
.scale_sqrt(rd.config.preview.samples)
.as_color();
let row = scaled_row * scale_height;
let col = scaled_col * scale_width;
for scale_h in 0..scale_height {
for scale_w in 0..scale_width {
buf[offset
+ (row + scale_h) * image.screen_width
+ col
+ scale_w] = color;
}
}
}
}
})
}
}
impl Renderer for CpuRendererScaled {
fn render(&self, rd: RenderData) -> Result<(), crate::error::TracerError> {
let scale_width = get_highest_divdable(
rd.image.width / rd.config.render.num_threads_width,
rd.config.preview.scale,
);
let scale_height = get_highest_divdable(
rd.image.height / rd.config.render.num_threads_height,
rd.config.preview.scale,
);
CpuRenderer::prepare_threads(&rd).and_then(|(cam, images)| {
images
.into_par_iter()
.map(|image| self.raytrace(&rd, &cam, &image, (scale_width, scale_height)))
.collect::<Result<(), TracerError>>()
})
}
}
|