[gtk+/wip/baedert/drawing] gl renderer: Implement linear gradient nodes
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/baedert/drawing] gl renderer: Implement linear gradient nodes
- Date: Sat, 1 Jul 2017 13:38:02 +0000 (UTC)
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]