diff options
Diffstat (limited to 'graphics')
| -rw-r--r-- | graphics/Cargo.toml | 1 | ||||
| -rw-r--r-- | graphics/src/gradient.rs | 82 | 
2 files changed, 60 insertions, 23 deletions
diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml index 0e22227d..02621695 100644 --- a/graphics/Cargo.toml +++ b/graphics/Cargo.toml @@ -18,6 +18,7 @@ web-colors = []  [dependencies]  glam = "0.24" +half = "2.2.1"  log = "0.4"  raw-window-handle = "0.5"  thiserror = "1.0" diff --git a/graphics/src/gradient.rs b/graphics/src/gradient.rs index d26b5665..3f5d0509 100644 --- a/graphics/src/gradient.rs +++ b/graphics/src/gradient.rs @@ -7,6 +7,7 @@ use crate::color;  use crate::core::gradient::ColorStop;  use crate::core::{self, Color, Point, Rectangle}; +use half::f16;  use std::cmp::Ordering;  #[derive(Debug, Clone, PartialEq)] @@ -99,61 +100,96 @@ impl Linear {      /// Packs the [`Gradient`] for use in shader code.      pub fn pack(&self) -> Packed { -        let mut data: [f32; 44] = [0.0; 44]; +        let mut colors = [[0u32; 2]; 8]; +        let mut offsets = [f16::from(0u8); 8];          for (index, stop) in self.stops.iter().enumerate() {              let [r, g, b, a] =                  color::pack(stop.map_or(Color::default(), |s| s.color))                      .components(); -            data[index * 4] = r; -            data[(index * 4) + 1] = g; -            data[(index * 4) + 2] = b; -            data[(index * 4) + 3] = a; +            colors[index] = [ +                pack_f16s([f16::from_f32(r), f16::from_f32(g)]), +                pack_f16s([f16::from_f32(b), f16::from_f32(a)]), +            ]; -            data[32 + index] = stop.map_or(2.0, |s| s.offset); +            offsets[index] = +                stop.map_or(f16::from_f32(2.0), |s| f16::from_f32(s.offset));          } -        data[40] = self.start.x; -        data[41] = self.start.y; -        data[42] = self.end.x; -        data[43] = self.end.y; +        let offsets = [ +            pack_f16s([offsets[0], offsets[1]]), +            pack_f16s([offsets[2], offsets[3]]), +            pack_f16s([offsets[4], offsets[5]]), +            pack_f16s([offsets[6], offsets[7]]), +        ]; -        Packed(data) +        let direction = [self.start.x, self.start.y, self.end.x, self.end.y]; + +        Packed { +            colors, +            offsets, +            direction, +        }      }  }  /// Packed [`Gradient`] data for use in shader code.  #[derive(Debug, Copy, Clone, PartialEq)]  #[repr(C)] -pub struct Packed([f32; 44]); +pub struct Packed { +    // 8 colors, each channel = 16 bit float, 2 colors packed into 1 u32 +    colors: [[u32; 2]; 8], +    // 8 offsets, 8x 16 bit floats packed into 4 u32s +    offsets: [u32; 4], +    direction: [f32; 4], +}  /// Creates a new [`Packed`] gradient for use in shader code.  pub fn pack(gradient: &core::Gradient, bounds: Rectangle) -> Packed {      match gradient {          core::Gradient::Linear(linear) => { -            let mut data: [f32; 44] = [0.0; 44]; +            let mut colors = [[0u32; 2]; 8]; +            let mut offsets = [f16::from(0u8); 8];              for (index, stop) in linear.stops.iter().enumerate() {                  let [r, g, b, a] =                      color::pack(stop.map_or(Color::default(), |s| s.color))                          .components(); -                data[index * 4] = r; -                data[(index * 4) + 1] = g; -                data[(index * 4) + 2] = b; -                data[(index * 4) + 3] = a; -                data[32 + index] = stop.map_or(2.0, |s| s.offset); +                colors[index] = [ +                    pack_f16s([f16::from_f32(r), f16::from_f32(g)]), +                    pack_f16s([f16::from_f32(b), f16::from_f32(a)]), +                ]; + +                offsets[index] = stop +                    .map_or(f16::from_f32(2.0), |s| f16::from_f32(s.offset));              } +            let offsets = [ +                pack_f16s([offsets[0], offsets[1]]), +                pack_f16s([offsets[2], offsets[3]]), +                pack_f16s([offsets[4], offsets[5]]), +                pack_f16s([offsets[6], offsets[7]]), +            ]; +              let (start, end) = linear.angle.to_distance(&bounds); -            data[40] = start.x; -            data[41] = start.y; -            data[42] = end.x; -            data[43] = end.y; +            let direction = [start.x, start.y, end.x, end.y]; -            Packed(data) +            Packed { +                colors, +                offsets, +                direction, +            }          }      }  } + +/// Packs two f16s into one u32. +fn pack_f16s(f: [f16; 2]) -> u32 { +    let one = (f[0].to_bits() as u32) << 16; +    let two = f[1].to_bits() as u32; + +    one | two +}  | 
