hyperion/image/
reducer.rs1use crate::models::{Color16, Led};
2
3use super::Image;
4
5#[derive(Debug, Default)]
6pub struct Reducer {
7 spec: Vec<LedSpec>,
8 spec_width: u16,
9 spec_height: u16,
10}
11
12#[derive(Debug)]
13struct LedSpec {
14 lxmin: u16,
15 lxmax: u16,
16 lymin: u16,
17 lymax: u16,
18}
19
20impl LedSpec {
21 pub fn new(spec: &Led, width: u16, height: u16, fwidth: f32, fheight: f32) -> Self {
22 let lxmin = spec.hmin * fwidth;
23 let lxmax = spec.hmax * fwidth;
24 let lymin = spec.vmin * fheight;
25 let lymax = spec.vmax * fheight;
26
27 Self {
28 lxmin: lxmin.floor() as u16,
29 lxmax: (lxmax.ceil() as u16).min(width - 1),
30 lymin: lymin.floor() as u16,
31 lymax: (lymax.ceil() as u16).min(height - 1),
32 }
33 }
34}
35
36impl Reducer {
37 pub fn reset(&mut self, width: u16, height: u16, leds: &[Led]) {
38 self.spec_width = width;
39 self.spec_height = height;
40
41 let fwidth = width as f32;
42 let fheight = height as f32;
43
44 self.spec.clear();
45 self.spec.reserve(leds.len());
46
47 for spec in leds.iter() {
48 self.spec
49 .push(LedSpec::new(spec, width, height, fwidth, fheight));
50 }
51 }
52
53 pub fn reduce(&mut self, image: &impl Image, leds: &[Led], color_data: &mut [Color16]) {
54 let width = image.width();
55 let height = image.height();
56
57 if self.spec_width != width || self.spec_height != height || self.spec.len() != leds.len() {
58 self.reset(width, height, leds);
59 }
60
61 for (spec, value) in self.spec.iter().zip(color_data.iter_mut()) {
62 let mut r_acc = 0u64;
63 let mut g_acc = 0u64;
64 let mut b_acc = 0u64;
65 let mut cnt = 0u64;
66
67 for y in spec.lymin..=spec.lymax {
68 for x in spec.lxmin..=spec.lxmax {
69 let rgb = unsafe { image.color_at_unchecked(x as _, y as _) };
71 let area = 255;
72
73 let (r, g, b) = rgb.into_components();
74 r_acc += (r as u64 * 255) * area;
75 g_acc += (g as u64 * 255) * area;
76 b_acc += (b as u64 * 255) * area;
77 cnt += area;
78 }
79 }
80
81 *value = Color16::new(
82 ((r_acc / cnt.max(1)) * 65535 / (255 * 255)).min(u16::MAX as _) as u16,
83 ((g_acc / cnt.max(1)) * 65535 / (255 * 255)).min(u16::MAX as _) as u16,
84 ((b_acc / cnt.max(1)) * 65535 / (255 * 255)).min(u16::MAX as _) as u16,
85 );
86 }
87 }
88}