bevy-julia/src/colorramp.rs

112 lines
2.9 KiB
Rust

#[derive(Clone, Copy, Debug)]
pub struct Color {
r: f32,
g: f32,
b: f32,
a: f32,
}
impl std::ops::Mul<f32> for Color {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Color {
r: self.r * rhs,
g: self.g * rhs,
b: self.b * rhs,
a: self.a * rhs,
}
}
}
impl std::ops::Add for Color {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Color {
r: self.r + rhs.r,
g: self.g + rhs.g,
b: self.b + rhs.b,
a: self.a + rhs.a,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Tick {
position: f32,
color: Color,
}
#[derive(Debug)]
pub struct ColorRamp {
ticks: Vec<Tick>,
}
impl ColorRamp {
pub fn new() -> ColorRamp {
ColorRamp { ticks: vec![] }
}
pub fn add(&mut self, position: f32, r: f32, g: f32, b: f32, a: f32) {
self.ticks.push(Tick {
position,
color: Color { r, g, b, a },
});
self.ticks
.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
}
pub fn interpolate(&self, pos: f32) -> Option<Color> {
let mut span: Option<(&Tick, &Tick)> = None;
for i in 0..self.ticks.len() - 1 {
let t1 = &self.ticks[i];
let t2 = &self.ticks[i + 1];
if (pos >= t1.position) && (pos <= t2.position) {
span = Some((t1, t2));
break;
}
}
let (t1, t2) = span?;
let relpos = pos - t1.position;
let factor = relpos / (t2.position - t1.position);
Some(t1.color * (1.0 - factor) + t2.color * factor)
}
pub fn range(&self) -> Option<(f32, f32)> {
if self.ticks.len() < 2 {
None
} else {
Some((
self.ticks.first().unwrap().position,
self.ticks.last().unwrap().position,
))
}
}
pub fn build_texture_data(&self, width: usize, height: usize) -> Option<Vec<u8>> {
let (t0, t1) = self.range()?;
let range = t1 - t0;
let step = range / width as f32;
let mut result: Vec<u8> = vec![];
for p in 0..width - 1 {
let pos = t0 + p as f32 * step;
let col = self.interpolate(pos).unwrap();
result.push((col.r * 255.).round() as u8);
result.push((col.g * 255.).round() as u8);
result.push((col.b * 255.).round() as u8);
result.push((col.a * 255.).round() as u8);
}
let last = self.interpolate(t1).unwrap();
result.push((last.r * 255.).round() as u8);
result.push((last.g * 255.).round() as u8);
result.push((last.b * 255.).round() as u8);
result.push((last.a * 255.).round() as u8);
let mut repeated = result.clone();
for _ in 0..height - 1 {
repeated.append(&mut result.clone());
}
Some(repeated)
}
}