fast_heatmap/
lib.rs

1#![no_std]
2/// Gets the color of a point with the specified value, using the default palette
3/// 
4/// The input is in the range 0-u16::MAX and the output is RGBA
5pub fn get_color(value: u16) -> u32 {
6    let blocks = MAP_COLORS_LENGTH - 1;
7    let block_of_color = value as u32 * blocks as u32;
8    let block_idx = (block_of_color >> u16::BITS) as usize;
9    let perc_of_color = block_of_color as u16;
10
11    let target = MAP_COLORS[block_idx];
12    let next = MAP_COLORS[block_idx + 1];
13
14    let delta_r = red(next) as i32 - red(target) as i32;
15    let delta_g = green(next) as i32 - green(target) as i32;
16    let delta_b = blue(next) as i32 - blue(target) as i32;
17
18    let r = red(target) + ((delta_r * perc_of_color as i32) >> u16::BITS) as u32;
19    let g = green(target) + ((delta_g * perc_of_color as i32) >> u16::BITS) as u32;
20    let b = blue(target) + ((delta_b * perc_of_color as i32) >> u16::BITS) as u32;
21
22    return pix(r, g, b);
23}
24
25
26/// Gets the color of a point with the specified value, using the default palette
27/// 
28/// The input is in the range 0-u16::MAX and the output is RGBA
29/// 
30/// This is a function that operates on 8 value chunks, and is easily auto vectorized
31pub fn get_color_block(values: [u16; 8], buf: &mut [u32; 8]) {
32
33    for (i, value) in values.iter().enumerate() {
34        let blocks = MAP_COLORS_LENGTH - 1;
35        let block_of_color = *value as u32 * blocks as u32;
36        let block_idx = (block_of_color >> u16::BITS) as usize;
37        let perc_of_color = block_of_color as u16;
38
39        let target = MAP_COLORS[block_idx];
40        let next = MAP_COLORS[block_idx + 1];
41
42        let delta_r = red(next) as i32 - red(target) as i32;
43        let delta_g = green(next) as i32 - green(target) as i32;
44        let delta_b = blue(next) as i32 - blue(target) as i32;
45
46        let r = red(target) + ((delta_r * perc_of_color as i32) >> u16::BITS) as u32;
47        let g = green(target) + ((delta_g * perc_of_color as i32) >> u16::BITS) as u32;
48        let b = blue(target) + ((delta_b * perc_of_color as i32) >> u16::BITS) as u32;
49
50        buf[i] = pix(r, g, b);
51    }
52}
53
54/// Gets the color of a point with the specified value, using a custom specified palette
55/// 
56/// The input is in the range 0-u16::MAX and the output is RGBA
57pub fn get_color_custom<const X: usize>(value: u16, palette: [u32; X]) -> u32 {
58    let blocks = X - 1;
59    let block_of_color = value as u32 * blocks as u32;
60    let block_idx = (block_of_color >> u16::BITS) as usize;
61    let perc_of_color = block_of_color as u16;
62
63    let target = palette[block_idx];
64    let next = palette[block_idx + 1];
65
66    let delta_r = red(next) as i32 - red(target) as i32;
67    let delta_g = green(next) as i32 - green(target) as i32;
68    let delta_b = blue(next) as i32 - blue(target) as i32;
69
70    let r = red(target) + ((delta_r * perc_of_color as i32) >> u16::BITS) as u32;
71    let g = green(target) + ((delta_g * perc_of_color as i32) >> u16::BITS) as u32;
72    let b = blue(target) + ((delta_b * perc_of_color as i32) >> u16::BITS) as u32;
73
74    return pix(r, g, b);
75}
76
77
78/// Gets the color of a point with the specified value, using a custom specified palette
79/// 
80/// The input is in the range 0-u16::MAX and the output is RGBA
81/// 
82/// This is a function that operates on 8 value chunks, and is easily auto vectorized
83pub fn get_color_block_custom<const X: usize>(values: [u16; 8], buf: &mut [u32; 8], palette: [u32; X]) {
84
85    for (i, value) in values.iter().enumerate() {
86        let blocks = X - 1;
87        let block_of_color = *value as u32 * blocks as u32;
88        let block_idx = (block_of_color >> u16::BITS) as usize;
89        let perc_of_color = block_of_color as u16;
90
91        let target = palette[block_idx];
92        let next = palette[block_idx + 1];
93
94        let delta_r = red(next) as i32 - red(target) as i32;
95        let delta_g = green(next) as i32 - green(target) as i32;
96        let delta_b = blue(next) as i32 - blue(target) as i32;
97
98        let r = red(target) + ((delta_r * perc_of_color as i32) >> u16::BITS) as u32;
99        let g = green(target) + ((delta_g * perc_of_color as i32) >> u16::BITS) as u32;
100        let b = blue(target) + ((delta_b * perc_of_color as i32) >> u16::BITS) as u32;
101
102        buf[i] = pix(r, g, b);
103    }
104}
105
106#[inline(always)]
107fn red(pix: u32) -> u32 {
108    (pix & 0xFF000000) >> 24
109}
110
111#[inline(always)]
112fn green(pix: u32) -> u32 {
113    (pix & 0x00FF0000) >> 16
114}
115
116#[inline(always)]
117fn blue(pix: u32) -> u32 {
118    (pix & 0x0000FF00) >> 8
119}
120
121#[inline(always)]
122fn pix(r: u32, g: u32, b: u32) -> u32 {
123    (0xFF << 24) | (b << 16) | (g << 8) | r
124}
125
126const MAP_COLORS_LENGTH: usize = 7;
127
128const MAP_COLORS: [u32; MAP_COLORS_LENGTH] = [
129    0x000000FF, // Black
130    0x0000FFFF, // Blue,
131    0x00FFFFFF, // Cyan,
132    0x00FF00FF, // Green,
133    0xFFFF00FF, // Yellow,
134    0xFF0000FF, // Red,
135    0xFFFFFFFF, // White
136];