From 6551a0b2ab6c831dd1d3646ecf55180339275e22 Mon Sep 17 00:00:00 2001
From: Bingus <shankern@protonmail.com>
Date: Thu, 11 May 2023 09:12:06 -0700
Subject: Added support for gradients as background variants + other
 optimizations.

---
 wgpu/src/geometry.rs | 111 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 81 insertions(+), 30 deletions(-)

(limited to 'wgpu/src/geometry.rs')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index 7e17a7ad..e26d9278 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,10 +1,11 @@
 //! Build and draw geometry.
-use crate::core::{Gradient, Point, Rectangle, Size, Vector};
+use crate::core::{Point, Rectangle, Size, Vector};
 use crate::graphics::geometry::fill::{self, Fill};
 use crate::graphics::geometry::{
     LineCap, LineDash, LineJoin, Path, Stroke, Style, Text,
 };
 use crate::graphics::primitive::{self, Primitive};
+use crate::graphics::Gradient;
 
 use lyon::geom::euclid;
 use lyon::tessellation;
@@ -23,10 +24,7 @@ pub struct Frame {
 
 enum Buffer {
     Solid(tessellation::VertexBuffers<primitive::ColoredVertex2D, u32>),
-    Gradient(
-        tessellation::VertexBuffers<primitive::Vertex2D, u32>,
-        Gradient,
-    ),
+    Gradient(tessellation::VertexBuffers<primitive::GradientVertex2D, u32>),
 }
 
 struct BufferStack {
@@ -48,12 +46,11 @@ impl BufferStack {
                     ));
                 }
             },
-            Style::Gradient(gradient) => match self.stack.last() {
-                Some(Buffer::Gradient(_, last)) if gradient == last => {}
+            Style::Gradient(_) => match self.stack.last() {
+                Some(Buffer::Gradient(_)) => {}
                 _ => {
                     self.stack.push(Buffer::Gradient(
                         tessellation::VertexBuffers::new(),
-                        gradient.clone(),
                     ));
                 }
             },
@@ -73,9 +70,14 @@ impl BufferStack {
                     TriangleVertex2DBuilder(color.into_linear()),
                 ))
             }
-            (Style::Gradient(_), Buffer::Gradient(buffer, _)) => Box::new(
-                tessellation::BuffersBuilder::new(buffer, Vertex2DBuilder),
-            ),
+            (Style::Gradient(gradient), Buffer::Gradient(buffer)) => {
+                Box::new(tessellation::BuffersBuilder::new(
+                    buffer,
+                    GradientVertex2DBuilder {
+                        gradient: gradient.clone(),
+                    },
+                ))
+            }
             _ => unreachable!(),
         }
     }
@@ -91,9 +93,14 @@ impl BufferStack {
                     TriangleVertex2DBuilder(color.into_linear()),
                 ))
             }
-            (Style::Gradient(_), Buffer::Gradient(buffer, _)) => Box::new(
-                tessellation::BuffersBuilder::new(buffer, Vertex2DBuilder),
-            ),
+            (Style::Gradient(gradient), Buffer::Gradient(buffer)) => {
+                Box::new(tessellation::BuffersBuilder::new(
+                    buffer,
+                    GradientVertex2DBuilder {
+                        gradient: gradient.clone(),
+                    },
+                ))
+            }
             _ => unreachable!(),
         }
     }
@@ -131,11 +138,13 @@ impl Transform {
     }
 
     fn transform_gradient(&self, mut gradient: Gradient) -> Gradient {
-        let (start, end) = match &mut gradient {
-            Gradient::Linear(linear) => (&mut linear.start, &mut linear.end),
-        };
-        self.transform_point(start);
-        self.transform_point(end);
+        match &mut gradient {
+            Gradient::Linear(linear) => {
+                self.transform_point(&mut linear.start);
+                self.transform_point(&mut linear.end);
+            }
+        }
+
         gradient
     }
 }
@@ -462,7 +471,7 @@ impl Frame {
                         })
                     }
                 }
-                Buffer::Gradient(buffer, gradient) => {
+                Buffer::Gradient(buffer) => {
                     if !buffer.indices.is_empty() {
                         self.primitives.push(Primitive::GradientMesh {
                             buffers: primitive::Mesh2D {
@@ -470,7 +479,6 @@ impl Frame {
                                 indices: buffer.indices,
                             },
                             size: self.size,
-                            gradient,
                         })
                     }
                 }
@@ -481,34 +489,38 @@ impl Frame {
     }
 }
 
-struct Vertex2DBuilder;
+struct GradientVertex2DBuilder {
+    gradient: Gradient,
+}
 
-impl tessellation::FillVertexConstructor<primitive::Vertex2D>
-    for Vertex2DBuilder
+impl tessellation::FillVertexConstructor<primitive::GradientVertex2D>
+    for GradientVertex2DBuilder
 {
     fn new_vertex(
         &mut self,
         vertex: tessellation::FillVertex<'_>,
-    ) -> primitive::Vertex2D {
+    ) -> primitive::GradientVertex2D {
         let position = vertex.position();
 
-        primitive::Vertex2D {
+        primitive::GradientVertex2D {
             position: [position.x, position.y],
+            gradient: pack_gradient(&self.gradient),
         }
     }
 }
 
-impl tessellation::StrokeVertexConstructor<primitive::Vertex2D>
-    for Vertex2DBuilder
+impl tessellation::StrokeVertexConstructor<primitive::GradientVertex2D>
+    for GradientVertex2DBuilder
 {
     fn new_vertex(
         &mut self,
         vertex: tessellation::StrokeVertex<'_, '_>,
-    ) -> primitive::Vertex2D {
+    ) -> primitive::GradientVertex2D {
         let position = vertex.position();
 
-        primitive::Vertex2D {
+        primitive::GradientVertex2D {
             position: [position.x, position.y],
+            gradient: pack_gradient(&self.gradient),
         }
     }
 }
@@ -611,3 +623,42 @@ pub(super) fn dashed(path: &Path, line_dash: LineDash<'_>) -> Path {
         );
     })
 }
+
+/// Packs the [`Gradient`] for use in shader code.
+fn pack_gradient(gradient: &Gradient) -> [f32; 44] {
+    match gradient {
+        Gradient::Linear(linear) => {
+            let mut pack: [f32; 44] = [0.0; 44];
+            let mut offsets: [f32; 8] = [2.0; 8];
+
+            for (index, stop) in linear.color_stops.iter().enumerate() {
+                let [r, g, b, a] = stop
+                    .map_or(crate::core::Color::default(), |s| s.color)
+                    .into_linear();
+
+                pack[index * 4] = r;
+                pack[(index * 4) + 1] = g;
+                pack[(index * 4) + 2] = b;
+                pack[(index * 4) + 3] = a;
+
+                offsets[index] = stop.map_or(2.0, |s| s.offset);
+            }
+
+            pack[32] = offsets[0];
+            pack[33] = offsets[1];
+            pack[34] = offsets[2];
+            pack[35] = offsets[3];
+            pack[36] = offsets[4];
+            pack[37] = offsets[5];
+            pack[38] = offsets[6];
+            pack[39] = offsets[7];
+
+            pack[40] = linear.start.x;
+            pack[41] = linear.start.y;
+            pack[42] = linear.end.x;
+            pack[43] = linear.end.y;
+
+            pack
+        }
+    }
+}
-- 
cgit