[gtk+/wip/baedert/drawing] gl renderer: Implement linear gradient nodes



commit 1c76fedf58fd90463fe7c201507de04bace4da12
Author: Timm Bäder <mail baedert org>
Date:   Sat Jul 1 12:54:55 2017 +0200

    gl renderer: Implement linear gradient nodes

 gsk/Makefile.am                            |    2 +
 gsk/gskglrenderer.c                        |  118 +++++++++++++++++++++++++---
 gsk/resources/glsl/gl3_common.fs.glsl      |    2 +
 gsk/resources/glsl/linear_gradient.fs.glsl |   36 +++++++++
 gsk/resources/glsl/linear_gradient.vs.glsl |    6 ++
 5 files changed, 154 insertions(+), 10 deletions(-)
---
diff --git a/gsk/Makefile.am b/gsk/Makefile.am
index caef1cc..7fe143e 100644
--- a/gsk/Makefile.am
+++ b/gsk/Makefile.am
@@ -121,6 +121,8 @@ gsk_private_source_shaders = \
        resources/glsl/blit.vs.glsl \
        resources/glsl/color.vs.glsl \
        resources/glsl/color.fs.glsl \
+       resources/glsl/linear_gradient.vs.glsl \
+       resources/glsl/linear_gradient.fs.glsl \
        resources/glsl/es2_common.fs.glsl \
        resources/glsl/es2_common.vs.glsl \
        resources/glsl/gl3_common.fs.glsl \
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 34a0215..05bedd2 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -21,6 +21,8 @@
 #define SHADER_VERSION_GL3_LEGACY       130
 #define SHADER_VERSION_GL3              150
 
+#define LINEAR_GRADIENT_MAX_STOPS 10 /* Same thing in the fragment shader */
+
 typedef struct {
   int id;
   /* Common locations (gl_common)*/
@@ -31,12 +33,20 @@ typedef struct {
   int position_location;
   int alpha_location;
   int blendMode_location;
+  int viewport_location;
 
   /* Shader-specific locations */
   union {
     struct {
       int color_location;
     };
+    struct {
+      int start_location;
+      int end_location;
+      int colors_location;
+      int offsets_location;
+      int n_stops_location;
+    };
   };
 } Program;
 
@@ -53,6 +63,7 @@ typedef struct {
 enum {
   MODE_COLOR = 1,
   MODE_TEXTURE,
+  MODE_LINEAR_GRADIENT,
   N_MODES
 };
 
@@ -76,8 +87,12 @@ typedef struct {
       GdkRGBA color;
     } color_data;
     struct {
-      int a,b;
-    } texture_data;
+      gsize n_stops;
+      float offsets[LINEAR_GRADIENT_MAX_STOPS];
+      float colors[LINEAR_GRADIENT_MAX_STOPS * 4];
+      graphene_point_t start;
+      graphene_point_t end;
+    } linear_gradient_data;
   };
 
   const char *name;
@@ -98,6 +113,7 @@ enum {
   MASK,
   ALPHA,
   BLEND_MODE,
+  VIEWPORT,
   N_UNIFORMS
 };
 
@@ -124,7 +140,7 @@ typedef enum {
   RENDER_SCISSOR
 } RenderMode;
 
-#define NUM_PROGRAMS 3
+#define NUM_PROGRAMS 4
 
 struct _GskGLRenderer
 {
@@ -133,6 +149,9 @@ struct _GskGLRenderer
   graphene_matrix_t mvp;
   graphene_frustum_t frustum;
 
+  float viewport_width;
+  float viewport_height;
+
   guint frame_buffer;
   guint depth_stencil_buffer;
   guint texture_id;
@@ -150,6 +169,7 @@ struct _GskGLRenderer
       Program blend_program;
       Program blit_program;
       Program color_program;
+      Program linear_gradient_program;
     };
     struct {
       Program programs[NUM_PROGRAMS];
@@ -247,6 +267,7 @@ init_common_locations (GskGLRenderer *self,
     gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[ALPHA]);
   prog->blendMode_location =
     gsk_shader_builder_get_uniform_location (self->shader_builder, prog->id, self->uniforms[BLEND_MODE]);
+  prog->viewport_location = glGetUniformLocation(prog->id, "uViewport");
 
   prog->position_location =
     gsk_shader_builder_get_attribute_location (self->shader_builder, prog->id, self->attributes[POSITION]);
@@ -271,7 +292,8 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   self->uniforms[MASK] = gsk_shader_builder_add_uniform (builder, "uMask");
   self->uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "uAlpha");
   self->uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "uBlendMode");
-  
+  self->uniforms[VIEWPORT] = gsk_shader_builder_add_uniform (builder, "uViewport");
+
   self->attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "aPosition");
   self->attributes[UV] = gsk_shader_builder_add_attribute (builder, "aUv");
 
@@ -348,11 +370,25 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       goto out;
     }
   init_common_locations (self, &self->color_program);
-  self->color_program.color_location = gsk_shader_builder_get_uniform_location (self->shader_builder,
-                                                                                self->color_program.id,
-                                                                                
g_quark_from_string("uColor"));
   self->color_program.color_location = glGetUniformLocation(self->color_program.id, "uColor");
-  g_assert(self->color_program.color_location >= 0);
+
+  self->linear_gradient_program.id =
+    gsk_shader_builder_create_program (builder, "linear_gradient.vs.glsl", "linear_gradient.fs.glsl", 
&shader_error);
+  if (shader_error != NULL)
+    {
+      g_propagate_prefixed_error (error,
+                                  shader_error,
+                                  "Unable to create 'linear_gradient' program: ");
+      g_object_unref (builder);
+      goto out;
+    }
+  init_common_locations (self, &self->linear_gradient_program);
+  self->linear_gradient_program.start_location = glGetUniformLocation(self->linear_gradient_program.id, 
"uStart");
+  self->linear_gradient_program.end_location = glGetUniformLocation(self->linear_gradient_program.id, 
"uEnd");
+  self->linear_gradient_program.colors_location = glGetUniformLocation(self->linear_gradient_program.id, 
"uColors");
+  self->linear_gradient_program.offsets_location = glGetUniformLocation(self->linear_gradient_program.id, 
"uOffsets");
+  g_assert (self->linear_gradient_program.offsets_location >= 0);
+  self->linear_gradient_program.n_stops_location = glGetUniformLocation(self->linear_gradient_program.id, 
"nStops");
 
   res = TRUE;
 
@@ -483,6 +519,9 @@ gsk_gl_renderer_resize_viewport (GskGLRenderer         *self,
                              scale_factor));
 
   glViewport (0, 0, width, height);
+
+  self->viewport_width = width;
+  self->viewport_height = height;
 }
 
 static void
@@ -505,8 +544,8 @@ gsk_gl_renderer_update_frustum (GskGLRenderer           *self,
 #define N_VERTICES      6
 
 static void
-render_item (GskGLRenderer *self,
-             RenderItem    *item)
+render_item (GskGLRenderer    *self,
+             const RenderItem *item)
 {
   float mvp[16];
   float opacity;
@@ -538,6 +577,30 @@ render_item (GskGLRenderer *self,
         }
       break;
 
+      case MODE_LINEAR_GRADIENT:
+        {
+          glUniform2f (item->render_data.program->start_location,
+                       item->linear_gradient_data.start.x,
+                       item->linear_gradient_data.start.y);
+
+          glUniform2f (item->render_data.program->end_location,
+                       item->linear_gradient_data.end.x,
+                       item->linear_gradient_data.end.y);
+
+          glUniform1i (item->render_data.program->n_stops_location,
+                       item->linear_gradient_data.n_stops);
+
+          glUniform4fv (item->render_data.program->colors_location,
+                        item->linear_gradient_data.n_stops * 4,
+                        item->linear_gradient_data.colors);
+
+          g_assert (item->render_data.program->offsets_location >= 0);
+          glUniform1fv (item->render_data.program->offsets_location,
+                        item->linear_gradient_data.n_stops,
+                        item->linear_gradient_data.offsets);
+        }
+      break;
+
       case MODE_TEXTURE:
         {
           g_assert(item->render_data.texture_id != 0);
@@ -569,6 +632,7 @@ render_item (GskGLRenderer *self,
   else
     opacity = item->opacity;
 
+  glUniform2f (item->render_data.program->viewport_location, self->viewport_width, self->viewport_height);
   glUniform1f (item->render_data.program->alpha_location, opacity);
 
   /* Pass the mvp to the vertex shader */
@@ -576,6 +640,8 @@ render_item (GskGLRenderer *self,
   graphene_matrix_to_float (&item->mvp, mvp);
   glUniformMatrix4fv (item->render_data.program->mvp_location, 1, GL_FALSE, mvp);
 
+
+
   /* Draw the quad */
   GSK_NOTE2 (OPENGL, TRANSFORMS,
              g_print ("Drawing item <%s>[%p] (w:%g, h:%g) with opacity: %g blend mode: %d\n",
@@ -841,6 +907,38 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
       }
       break;
 
+    case GSK_LINEAR_GRADIENT_NODE:
+      {
+        gsize i;
+        const GskColorStop *stops = gsk_linear_gradient_node_peek_color_stops (node);
+        gsize n_stops = gsk_linear_gradient_node_get_n_color_stops (node);
+        program_id = self->linear_gradient_program.id;
+        item.render_data.program = &self->linear_gradient_program;
+        item.mode = MODE_LINEAR_GRADIENT;
+
+        for (i = 0; i < MIN (n_stops, LINEAR_GRADIENT_MAX_STOPS); i ++)
+          {
+            item.linear_gradient_data.offsets[i] = (float)stops[i].offset;
+            item.linear_gradient_data.colors[(i * 4) + 0] = (float)stops[i].color.red;
+            item.linear_gradient_data.colors[(i * 4) + 1] = (float)stops[i].color.green;
+            item.linear_gradient_data.colors[(i * 4) + 2] = (float)stops[i].color.blue;
+            item.linear_gradient_data.colors[(i * 4) + 3] = (float)stops[i].color.alpha;
+          }
+
+        item.linear_gradient_data.n_stops = n_stops;
+        item.linear_gradient_data.start = *gsk_linear_gradient_node_peek_start (node);
+        item.linear_gradient_data.end = *gsk_linear_gradient_node_peek_end (node);
+      }
+      break;
+
+    case GSK_ROUNDED_CLIP_NODE:
+      {
+        GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
+
+        gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
+      }
+      return;
+
     case GSK_COLOR_MATRIX_NODE:
       {
         GskRenderNode *child = gsk_color_matrix_node_get_child (node);
diff --git a/gsk/resources/glsl/gl3_common.fs.glsl b/gsk/resources/glsl/gl3_common.fs.glsl
index 50f72f5..3308851 100644
--- a/gsk/resources/glsl/gl3_common.fs.glsl
+++ b/gsk/resources/glsl/gl3_common.fs.glsl
@@ -6,6 +6,8 @@ uniform mat4 uMVP;
 uniform float uAlpha;
 uniform int uBlendMode;
 
+uniform vec2 uViewport;
+
 in vec2 vUv;
 
 out vec4 outputColor;
diff --git a/gsk/resources/glsl/linear_gradient.fs.glsl b/gsk/resources/glsl/linear_gradient.fs.glsl
new file mode 100644
index 0000000..a3cf4c5
--- /dev/null
+++ b/gsk/resources/glsl/linear_gradient.fs.glsl
@@ -0,0 +1,36 @@
+const int MAX_STOPS = 10;
+
+uniform vec4 uColors[MAX_STOPS];
+uniform float uOffsets[MAX_STOPS];
+
+uniform vec2 uStart;
+uniform vec2 uEnd;
+uniform int nStops;
+
+void main() {
+  vec2 pos = gl_FragCoord.xy;
+  pos.y = uViewport.y - pos.y;
+
+  vec2 dist = uEnd - uStart;
+  vec2 dir = dist / length(dist);
+
+  // pos projected on the line between uStart and uEnd
+  vec2 projection = (dot(pos - uStart, dir) / dot(dir, dir)) * dir;
+  projection += uStart;
+
+  vec2 last = uStart;
+  for (int i = 1; i < nStops; i ++) {
+    vec2 point = uStart + (dist * uOffsets[i]);
+    float max_dist = length(point - last); // distance between current stop and last one
+
+    if (length(last - projection) <= max_dist &&
+        length(point - projection) <= max_dist) {
+      float percentage = length(projection - last) / max_dist;
+      setOutputColor(mix(uColors[i - 1], uColors[i], percentage));
+      return;
+    }
+    last = point;
+  }
+
+  setOutputColor(uColors[nStops - 1]);
+}
diff --git a/gsk/resources/glsl/linear_gradient.vs.glsl b/gsk/resources/glsl/linear_gradient.vs.glsl
new file mode 100644
index 0000000..1208513
--- /dev/null
+++ b/gsk/resources/glsl/linear_gradient.vs.glsl
@@ -0,0 +1,6 @@
+void main() {
+  gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
+
+  // Flip the sampling
+  vUv = vec2(aUv.x, aUv.y);
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]