diff --git a/demos/gtk-demo/iconscroll.c b/demos/gtk-demo/iconscroll.c
index 9e2fe9dc8a..2eb9aa6e92 100644
--- a/demos/gtk-demo/iconscroll.c
+++ b/demos/gtk-demo/iconscroll.c
@@ -13,7 +13,7 @@ static GtkWidget *window = NULL;
static GtkWidget *scrolledwindow;
static int selected;
-#define N_WIDGET_TYPES 7
+#define N_WIDGET_TYPES 8
static int hincrement = 5;
@@ -110,6 +110,41 @@ populate_text (gboolean highlight)
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), textview);
}
+static void
+populate_emoji_text (void)
+{
+ GtkWidget *textview;
+ GtkTextBuffer *buffer;
+ GString *s;
+
+ s = g_string_sized_new (1000 * 30 * 4);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ if (i % 2)
+ g_string_append (s, "x");
+ for (int j = 0; j < 30; j++)
+ g_string_append (s, "💓x");
+ g_string_append (s, "\n");
+ }
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (buffer, s->str, s->len);
+
+ g_string_free (s, TRUE);
+
+ textview = gtk_text_view_new ();
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
+
+ hincrement = 0;
+ vincrement = 5;
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), textview);
+}
+
static void
populate_image (void)
{
@@ -224,21 +259,26 @@ set_widget_type (int type)
break;
case 3:
+ gtk_window_set_title (GTK_WINDOW (window), "Scrolling text with Emoji");
+ populate_emoji_text ();
+ break;
+
+ case 4:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a big image");
populate_image ();
break;
- case 4:
+ case 5:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a list");
populate_list ();
break;
- case 5:
+ case 6:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a columned list");
populate_list2 ();
break;
- case 6:
+ case 7:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a grid");
populate_grid ();
break;
diff --git a/gsk/gen-gsk-gresources-xml.py b/gsk/gen-gsk-gresources-xml.py
index 5db5044b09..16a2c4042a 100644
--- a/gsk/gen-gsk-gresources-xml.py
+++ b/gsk/gen-gsk-gresources-xml.py
@@ -20,13 +20,17 @@ def replace_if_changed(new, old):
else:
os.remove(new)
-source_shaders = []
+gl_source_shaders = []
+ngl_source_shaders = []
vulkan_compiled_shaders = []
vulkan_shaders = []
for f in sys.argv[2:]:
if f.endswith('.glsl'):
- source_shaders.append(f)
+ if f.startswith('ngl'):
+ ngl_source_shaders.append(f);
+ else:
+ gl_source_shaders.append(f)
elif f.endswith('.spv'):
vulkan_compiled_shaders.append(f)
elif f.endswith('.frag') or f.endswith('.vert'):
@@ -40,11 +44,16 @@ xml = '''
'''
-for f in source_shaders:
+for f in gl_source_shaders:
xml += ' resources/glsl/{0}\n'.format(os.path.basename(f))
xml += '\n'
+for f in ngl_source_shaders:
+ xml += ' ngl/resources/{0}\n'.format(os.path.basename(f))
+
+xml += '\n'
+
for f in vulkan_compiled_shaders:
xml += ' resources/vulkan/{0}\n'.format(os.path.basename(f))
diff --git a/gsk/meson.build b/gsk/meson.build
index dd1ac34ff9..8f9a6281c0 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -20,6 +20,28 @@ gsk_private_gl_shaders = [
'resources/glsl/custom.glsl',
]
+gsk_private_ngl_shaders = [
+ 'ngl/resources/preamble.glsl',
+ 'ngl/resources/preamble.fs.glsl',
+ 'ngl/resources/preamble.vs.glsl',
+ 'ngl/resources/border.glsl',
+ 'ngl/resources/blit.glsl',
+ 'ngl/resources/coloring.glsl',
+ 'ngl/resources/color.glsl',
+ 'ngl/resources/linear_gradient.glsl',
+ 'ngl/resources/radial_gradient.glsl',
+ 'ngl/resources/conic_gradient.glsl',
+ 'ngl/resources/color_matrix.glsl',
+ 'ngl/resources/blur.glsl',
+ 'ngl/resources/inset_shadow.glsl',
+ 'ngl/resources/outset_shadow.glsl',
+ 'ngl/resources/unblurred_outset_shadow.glsl',
+ 'ngl/resources/cross_fade.glsl',
+ 'ngl/resources/blend.glsl',
+ 'ngl/resources/repeat.glsl',
+ 'ngl/resources/custom.glsl',
+]
+
gsk_public_sources = files([
'gskdiff.c',
'gskcairorenderer.c',
@@ -150,6 +172,7 @@ gsk_resources_xml = configure_file(output: 'gsk.resources.xml',
find_program('gen-gsk-gresources-xml.py'),
'@OUTPUT@',
gsk_private_gl_shaders,
+ gsk_private_ngl_shaders,
gsk_private_vulkan_compiled_shaders,
gsk_private_vulkan_shaders
],
diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c
index 9426c199b1..7d5a8b30be 100644
--- a/gsk/ngl/gsknglcommandqueue.c
+++ b/gsk/ngl/gsknglcommandqueue.c
@@ -1096,6 +1096,12 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue *self,
sizeof (GskNglDrawVertex),
(void *) G_STRUCT_OFFSET (GskNglDrawVertex, uv));
+ /* 2 = color location */
+ glEnableVertexAttribArray (2);
+ glVertexAttribPointer (2, 4, GL_FLOAT, GL_FALSE,
+ sizeof (GskNglDrawVertex),
+ (void *) G_STRUCT_OFFSET (GskNglDrawVertex, color));
+
/* Setup initial scissor clip */
if (scissor != NULL)
{
diff --git a/gsk/ngl/gskngldriver.c b/gsk/ngl/gskngldriver.c
index 692e6a9d5d..3d910e5d51 100644
--- a/gsk/ngl/gskngldriver.c
+++ b/gsk/ngl/gskngldriver.c
@@ -336,17 +336,18 @@ gsk_ngl_driver_load_programs (GskNglDriver *self,
/* Setup preambles that are shared by all shaders */
gsk_ngl_compiler_set_preamble_from_resource (compiler,
GSK_NGL_COMPILER_ALL,
- "/org/gtk/libgsk/glsl/preamble.glsl");
+ "/org/gtk/libgsk/ngl/preamble.glsl");
gsk_ngl_compiler_set_preamble_from_resource (compiler,
GSK_NGL_COMPILER_VERTEX,
- "/org/gtk/libgsk/glsl/preamble.vs.glsl");
+ "/org/gtk/libgsk/ngl/preamble.vs.glsl");
gsk_ngl_compiler_set_preamble_from_resource (compiler,
GSK_NGL_COMPILER_FRAGMENT,
- "/org/gtk/libgsk/glsl/preamble.fs.glsl");
+ "/org/gtk/libgsk/ngl/preamble.fs.glsl");
/* Setup attributes that are provided via VBO */
gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
gsk_ngl_compiler_bind_attribute (compiler, "aUv", 1);
+ gsk_ngl_compiler_bind_attribute (compiler, "aColor", 2);
/* Use XMacros to register all of our programs and their uniforms */
#define GSK_NGL_NO_UNIFORMS
@@ -376,7 +377,6 @@ gsk_ngl_driver_load_programs (GskNglDriver *self,
uniforms \
\
gsk_ngl_program_uniforms_added (program, have_source); \
- \
if (have_alpha) \
gsk_ngl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f); \
\
@@ -1045,6 +1045,7 @@ gsk_ngl_driver_lookup_shader (GskNglDriver *self,
/* Setup attributes that are provided via VBO */
gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
gsk_ngl_compiler_bind_attribute (compiler, "aUv", 1);
+ gsk_ngl_compiler_bind_attribute (compiler, "aColor", 2);
if ((program = gsk_ngl_compiler_compile (compiler, NULL, "", error)))
{
diff --git a/gsk/ngl/gskngldriverprivate.h b/gsk/ngl/gskngldriverprivate.h
index 28199ec016..c50e112e86 100644
--- a/gsk/ngl/gskngldriverprivate.h
+++ b/gsk/ngl/gskngldriverprivate.h
@@ -58,13 +58,17 @@ typedef struct {
graphene_rect_t parent_rect; /* Valid when pointer_is_child */
} GskTextureKey;
-#define GSL_GK_NO_UNIFORMS UNIFORM_INVALID_##__COUNTER__
+#define GSK_NGL_NO_UNIFORMS CONCAT_EXPANDED(UNIFORM_INVALID_,__COUNTER__)
+#define CONCAT_EXPANDED(a,b) CONCAT_EXPANDED2(a,b)
+#define CONCAT_EXPANDED2(a,b) a##b
#define GSK_NGL_ADD_UNIFORM(pos, KEY, name) UNIFORM_##KEY = UNIFORM_SHARED_LAST + pos,
#define GSK_NGL_DEFINE_PROGRAM(name, resource, uniforms) enum { uniforms };
# include "gsknglprograms.defs"
#undef GSK_NGL_DEFINE_PROGRAM
#undef GSK_NGL_ADD_UNIFORM
-#undef GSL_GK_NO_UNIFORMS
+#undef GSK_NGL_NO_UNIFORMS
+#undef CONCAT_EXPANDED
+#undef CONCAT_EXPANDED2
#define GSK_TYPE_NGL_DRIVER (gsk_ngl_driver_get_type())
diff --git a/gsk/ngl/gsknglprograms.defs b/gsk/ngl/gsknglprograms.defs
index b0b797f0e9..e20cca2fa9 100644
--- a/gsk/ngl/gsknglprograms.defs
+++ b/gsk/ngl/gsknglprograms.defs
@@ -1,69 +1,66 @@
GSK_NGL_DEFINE_PROGRAM (blend,
- "/org/gtk/libgsk/glsl/blend.glsl",
+ "/org/gtk/libgsk/ngl/blend.glsl",
GSK_NGL_ADD_UNIFORM (1, BLEND_SOURCE2, u_source2)
GSK_NGL_ADD_UNIFORM (2, BLEND_MODE, u_mode))
GSK_NGL_DEFINE_PROGRAM (blit,
- "/org/gtk/libgsk/glsl/blit.glsl",
+ "/org/gtk/libgsk/ngl/blit.glsl",
GSK_NGL_NO_UNIFORMS)
GSK_NGL_DEFINE_PROGRAM (blur,
- "/org/gtk/libgsk/glsl/blur.glsl",
+ "/org/gtk/libgsk/ngl/blur.glsl",
GSK_NGL_ADD_UNIFORM (1, BLUR_RADIUS, u_blur_radius)
GSK_NGL_ADD_UNIFORM (2, BLUR_SIZE, u_blur_size)
GSK_NGL_ADD_UNIFORM (3, BLUR_DIR, u_blur_dir))
GSK_NGL_DEFINE_PROGRAM (border,
- "/org/gtk/libgsk/glsl/border.glsl",
- GSK_NGL_ADD_UNIFORM (1, BORDER_COLOR, u_color)
+ "/org/gtk/libgsk/ngl/border.glsl",
GSK_NGL_ADD_UNIFORM (2, BORDER_WIDTHS, u_widths)
GSK_NGL_ADD_UNIFORM (3, BORDER_OUTLINE_RECT, u_outline_rect))
GSK_NGL_DEFINE_PROGRAM (color,
- "/org/gtk/libgsk/glsl/color.glsl",
- GSK_NGL_ADD_UNIFORM (1, COLOR_COLOR, u_color))
+ "/org/gtk/libgsk/ngl/color.glsl",
+ GSK_NGL_NO_UNIFORMS)
GSK_NGL_DEFINE_PROGRAM (coloring,
- "/org/gtk/libgsk/glsl/coloring.glsl",
- GSK_NGL_ADD_UNIFORM (1, COLORING_COLOR, u_color))
+ "/org/gtk/libgsk/ngl/coloring.glsl",
+ GSK_NGL_NO_UNIFORMS)
GSK_NGL_DEFINE_PROGRAM (color_matrix,
- "/org/gtk/libgsk/glsl/color_matrix.glsl",
+ "/org/gtk/libgsk/ngl/color_matrix.glsl",
GSK_NGL_ADD_UNIFORM (1, COLOR_MATRIX_COLOR_MATRIX, u_color_matrix)
GSK_NGL_ADD_UNIFORM (2, COLOR_MATRIX_COLOR_OFFSET, u_color_offset))
GSK_NGL_DEFINE_PROGRAM (conic_gradient,
- "/org/gtk/libgsk/glsl/conic_gradient.glsl",
+ "/org/gtk/libgsk/ngl/conic_gradient.glsl",
GSK_NGL_ADD_UNIFORM (1, CONIC_GRADIENT_COLOR_STOPS, u_color_stops)
GSK_NGL_ADD_UNIFORM (2, CONIC_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
GSK_NGL_ADD_UNIFORM (3, CONIC_GRADIENT_GEOMETRY, u_geometry))
GSK_NGL_DEFINE_PROGRAM (cross_fade,
- "/org/gtk/libgsk/glsl/cross_fade.glsl",
+ "/org/gtk/libgsk/ngl/cross_fade.glsl",
GSK_NGL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress)
GSK_NGL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2))
GSK_NGL_DEFINE_PROGRAM (inset_shadow,
- "/org/gtk/libgsk/glsl/inset_shadow.glsl",
- GSK_NGL_ADD_UNIFORM (1, INSET_SHADOW_COLOR, u_color)
+ "/org/gtk/libgsk/ngl/inset_shadow.glsl",
GSK_NGL_ADD_UNIFORM (2, INSET_SHADOW_SPREAD, u_spread)
GSK_NGL_ADD_UNIFORM (3, INSET_SHADOW_OFFSET, u_offset)
GSK_NGL_ADD_UNIFORM (4, INSET_SHADOW_OUTLINE_RECT, u_outline_rect))
GSK_NGL_DEFINE_PROGRAM (linear_gradient,
- "/org/gtk/libgsk/glsl/linear_gradient.glsl",
+ "/org/gtk/libgsk/ngl/linear_gradient.glsl",
GSK_NGL_ADD_UNIFORM (1, LINEAR_GRADIENT_COLOR_STOPS, u_color_stops)
GSK_NGL_ADD_UNIFORM (2, LINEAR_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
GSK_NGL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points)
GSK_NGL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat))
GSK_NGL_DEFINE_PROGRAM (outset_shadow,
- "/org/gtk/libgsk/glsl/outset_shadow.glsl",
- GSK_NGL_ADD_UNIFORM (1, OUTSET_SHADOW_COLOR, u_color)
+ "/org/gtk/libgsk/ngl/outset_shadow.glsl",
GSK_NGL_ADD_UNIFORM (2, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
GSK_NGL_DEFINE_PROGRAM (radial_gradient,
- "/org/gtk/libgsk/glsl/radial_gradient.glsl",
+ "/org/gtk/libgsk/ngl/radial_gradient.glsl",
GSK_NGL_ADD_UNIFORM (1, RADIAL_GRADIENT_COLOR_STOPS, u_color_stops)
GSK_NGL_ADD_UNIFORM (2, RADIAL_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops)
GSK_NGL_ADD_UNIFORM (3, RADIAL_GRADIENT_REPEAT, u_repeat)
@@ -71,13 +68,12 @@ GSK_NGL_DEFINE_PROGRAM (radial_gradient,
GSK_NGL_ADD_UNIFORM (5, RADIAL_GRADIENT_GEOMETRY, u_geometry))
GSK_NGL_DEFINE_PROGRAM (repeat,
- "/org/gtk/libgsk/glsl/repeat.glsl",
+ "/org/gtk/libgsk/ngl/repeat.glsl",
GSK_NGL_ADD_UNIFORM (1, REPEAT_CHILD_BOUNDS, u_child_bounds)
GSK_NGL_ADD_UNIFORM (2, REPEAT_TEXTURE_RECT, u_texture_rect))
GSK_NGL_DEFINE_PROGRAM (unblurred_outset_shadow,
- "/org/gtk/libgsk/glsl/unblurred_outset_shadow.glsl",
- GSK_NGL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_COLOR, u_color)
+ "/org/gtk/libgsk/ngl/unblurred_outset_shadow.glsl",
GSK_NGL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
GSK_NGL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
GSK_NGL_ADD_UNIFORM (4, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c
index 93ca180133..8f67575564 100644
--- a/gsk/ngl/gsknglrenderjob.c
+++ b/gsk/ngl/gsknglrenderjob.c
@@ -142,6 +142,9 @@ struct _GskNglRenderJob
/* Our current alpha state as we process nodes */
float alpha;
+ /* Our current color state as we process nodes */
+ GdkRGBA color;
+
/* Offset (delta x,y) as we process nodes. Occasionally this is merged into
* a transform that is referenced from child transform nodes.
*/
@@ -395,6 +398,13 @@ gsk_ngl_render_job_set_alpha (GskNglRenderJob *job,
return alpha;
}
+static inline void
+gsk_ngl_render_job_set_color (GskNglRenderJob *job,
+ const GdkRGBA *color)
+{
+ job->color = *color;
+}
+
static void
extract_matrix_metadata (GskNglRenderModelview *modelview)
{
@@ -874,13 +884,81 @@ gsk_ngl_render_job_update_clip (GskNglRenderJob *job,
return TRUE;
}
+/* fill_vertex_data */
+static void
+gsk_ngl_render_job_draw_coords (GskNglRenderJob *job,
+ float min_x,
+ float min_y,
+ float max_x,
+ float max_y,
+ float min_u,
+ float min_v,
+ float max_u,
+ float max_v)
+{
+ GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
+
+ vertices[0].position[0] = min_x;
+ vertices[0].position[1] = min_y;
+ vertices[0].uv[0] = min_u;
+ vertices[0].uv[1] = min_v;
+ vertices[0].color[0] = job->color.red;
+ vertices[0].color[1] = job->color.green;
+ vertices[0].color[2] = job->color.blue;
+ vertices[0].color[3] = job->color.alpha;
+
+ vertices[1].position[0] = min_x;
+ vertices[1].position[1] = max_y;
+ vertices[1].uv[0] = min_u;
+ vertices[1].uv[1] = max_v;
+ vertices[1].color[0] = job->color.red;
+ vertices[1].color[1] = job->color.green;
+ vertices[1].color[2] = job->color.blue;
+ vertices[1].color[3] = job->color.alpha;
+
+ vertices[2].position[0] = max_x;
+ vertices[2].position[1] = min_y;
+ vertices[2].uv[0] = max_u;
+ vertices[2].uv[1] = min_v;
+ vertices[2].color[0] = job->color.red;
+ vertices[2].color[1] = job->color.green;
+ vertices[2].color[2] = job->color.blue;
+ vertices[2].color[3] = job->color.alpha;
+
+ vertices[3].position[0] = max_x;
+ vertices[3].position[1] = max_y;
+ vertices[3].uv[0] = max_u;
+ vertices[3].uv[1] = max_v;
+ vertices[3].color[0] = job->color.red;
+ vertices[3].color[1] = job->color.green;
+ vertices[3].color[2] = job->color.blue;
+ vertices[3].color[3] = job->color.alpha;
+
+ vertices[4].position[0] = min_x;
+ vertices[4].position[1] = max_y;
+ vertices[4].uv[0] = min_u;
+ vertices[4].uv[1] = max_v;
+ vertices[4].color[0] = job->color.red;
+ vertices[4].color[1] = job->color.green;
+ vertices[4].color[2] = job->color.blue;
+ vertices[4].color[3] = job->color.alpha;
+
+ vertices[5].position[0] = max_x;
+ vertices[5].position[1] = min_y;
+ vertices[5].uv[0] = max_u;
+ vertices[5].uv[1] = min_v;
+ vertices[5].color[0] = job->color.red;
+ vertices[5].color[1] = job->color.green;
+ vertices[5].color[2] = job->color.blue;
+ vertices[5].color[3] = job->color.alpha;
+}
+
/* load_vertex_data_with_region */
static inline void
gsk_ngl_render_job_load_vertices_from_offscreen (GskNglRenderJob *job,
const graphene_rect_t *bounds,
const GskNglRenderOffscreen *offscreen)
{
- GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
float min_x = job->offset_x + bounds->origin.x;
float min_y = job->offset_y + bounds->origin.y;
float max_x = min_x + bounds->size.width;
@@ -888,35 +966,9 @@ gsk_ngl_render_job_load_vertices_from_offscreen (GskNglRenderJob *jo
float y1 = offscreen->was_offscreen ? offscreen->area.y2 : offscreen->area.y;
float y2 = offscreen->was_offscreen ? offscreen->area.y : offscreen->area.y2;
- vertices[0].position[0] = min_x;
- vertices[0].position[1] = min_y;
- vertices[0].uv[0] = offscreen->area.x;
- vertices[0].uv[1] = y1;
-
- vertices[1].position[0] = min_x;
- vertices[1].position[1] = max_y;
- vertices[1].uv[0] = offscreen->area.x;
- vertices[1].uv[1] = y2;
-
- vertices[2].position[0] = max_x;
- vertices[2].position[1] = min_y;
- vertices[2].uv[0] = offscreen->area.x2;
- vertices[2].uv[1] = y1;
-
- vertices[3].position[0] = max_x;
- vertices[3].position[1] = max_y;
- vertices[3].uv[0] = offscreen->area.x2;
- vertices[3].uv[1] = y2;
-
- vertices[4].position[0] = min_x;
- vertices[4].position[1] = max_y;
- vertices[4].uv[0] = offscreen->area.x;
- vertices[4].uv[1] = y2;
-
- vertices[5].position[0] = max_x;
- vertices[5].position[1] = min_y;
- vertices[5].uv[0] = offscreen->area.x2;
- vertices[5].uv[1] = y1;
+ gsk_ngl_render_job_draw_coords (job,
+ min_x, min_y, max_x, max_y,
+ offscreen->area.x, y1, offscreen->area.x2, y2);
}
/* load_float_vertex_data */
@@ -927,41 +979,12 @@ gsk_ngl_render_job_draw (GskNglRenderJob *job,
float width,
float height)
{
- GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
float min_x = job->offset_x + x;
float min_y = job->offset_y + y;
float max_x = min_x + width;
float max_y = min_y + height;
- vertices[0].position[0] = min_x;
- vertices[0].position[1] = min_y;
- vertices[0].uv[0] = 0;
- vertices[0].uv[1] = 0;
-
- vertices[1].position[0] = min_x;
- vertices[1].position[1] = max_y;
- vertices[1].uv[0] = 0;
- vertices[1].uv[1] = 1;
-
- vertices[2].position[0] = max_x;
- vertices[2].position[1] = min_y;
- vertices[2].uv[0] = 1;
- vertices[2].uv[1] = 0;
-
- vertices[3].position[0] = max_x;
- vertices[3].position[1] = max_y;
- vertices[3].uv[0] = 1;
- vertices[3].uv[1] = 1;
-
- vertices[4].position[0] = min_x;
- vertices[4].position[1] = max_y;
- vertices[4].uv[0] = 0;
- vertices[4].uv[1] = 1;
-
- vertices[5].position[0] = max_x;
- vertices[5].position[1] = min_y;
- vertices[5].uv[0] = 1;
- vertices[5].uv[1] = 0;
+ gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 0, 1, 1);
}
/* load_vertex_data */
@@ -976,47 +999,6 @@ gsk_ngl_render_job_draw_rect (GskNglRenderJob *job,
bounds->size.height);
}
-/* fill_vertex_data */
-static void
-gsk_ngl_render_job_draw_coords (GskNglRenderJob *job,
- float min_x,
- float min_y,
- float max_x,
- float max_y)
-{
- GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
-
- vertices[0].position[0] = min_x;
- vertices[0].position[1] = min_y;
- vertices[0].uv[0] = 0;
- vertices[0].uv[1] = 1;
-
- vertices[1].position[0] = min_x;
- vertices[1].position[1] = max_y;
- vertices[1].uv[0] = 0;
- vertices[1].uv[1] = 0;
-
- vertices[2].position[0] = max_x;
- vertices[2].position[1] = min_y;
- vertices[2].uv[0] = 1;
- vertices[2].uv[1] = 1;
-
- vertices[3].position[0] = max_x;
- vertices[3].position[1] = max_y;
- vertices[3].uv[0] = 1;
- vertices[3].uv[1] = 0;
-
- vertices[4].position[0] = min_x;
- vertices[4].position[1] = max_y;
- vertices[4].uv[0] = 0;
- vertices[4].uv[1] = 0;
-
- vertices[5].position[0] = max_x;
- vertices[5].position[1] = min_y;
- vertices[5].uv[0] = 1;
- vertices[5].uv[1] = 1;
-}
-
/* load_offscreen_vertex_data */
static inline void
gsk_ngl_render_job_draw_offscreen_rect (GskNglRenderJob *job,
@@ -1027,7 +1009,7 @@ gsk_ngl_render_job_draw_offscreen_rect (GskNglRenderJob *job,
float max_x = min_x + bounds->size.width;
float max_y = min_y + bounds->size.height;
- gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y);
+ gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 1, 1, 0);
}
static inline void
@@ -1283,7 +1265,7 @@ blur_offscreen (GskNglRenderJob *job,
gsk_ngl_program_set_uniform2f (job->current_program,
UNIFORM_BLUR_DIR, 0,
1, 0);
- gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height);
+ gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height, 0, 1, 1, 0);
gsk_ngl_render_job_end_draw (job);
/* Bind second pass framebuffer and clear it */
@@ -1307,7 +1289,7 @@ blur_offscreen (GskNglRenderJob *job,
gsk_ngl_program_set_uniform2f (job->current_program,
UNIFORM_BLUR_DIR, 0,
0, 1);
- gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height);
+ gsk_ngl_render_job_draw_coords (job, 0, 0, texture_to_blur_width, texture_to_blur_height, 0, 1, 1, 0);
gsk_ngl_render_job_end_draw (job);
gsk_ngl_render_job_pop_modelview (job);
@@ -1381,9 +1363,7 @@ gsk_ngl_render_job_visit_color_node (GskNglRenderJob *job,
const GskRenderNode *node)
{
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_COLOR_COLOR, 0,
- gsk_color_node_get_color (node));
+ gsk_ngl_render_job_set_color (job, gsk_color_node_get_color (node));
gsk_ngl_render_job_draw_rect (job, &node->bounds);
gsk_ngl_render_job_end_draw (job);
}
@@ -1694,9 +1674,7 @@ gsk_ngl_render_job_visit_rect_border_node (GskNglRenderJob *job,
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_COLOR_COLOR, 0,
- &colors[0]);
+ gsk_ngl_render_job_set_color (job, &colors[0]);
gsk_ngl_render_job_draw_rect (job,
&GRAPHENE_RECT_INIT (origin->x,
@@ -1737,12 +1715,10 @@ gsk_ngl_render_job_visit_uniform_border_node (GskNglRenderJob *job,
gsk_ngl_render_job_transform_rounded_rect (job, rounded_outline, &outline);
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow));
+ gsk_ngl_render_job_set_color (job, &colors[0]);
gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
&outline);
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_INSET_SHADOW_COLOR, 0,
- &colors[0]);
gsk_ngl_program_set_uniform1f (job->current_program,
UNIFORM_INSET_SHADOW_SPREAD, 0,
widths[0]);
@@ -1758,7 +1734,7 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob *job,
const GskRenderNode *node)
{
const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node);
- const GdkRGBA *colors = gsk_border_node_get_colors (node);
+ const GdkRGBA *c = gsk_border_node_get_colors (node);
const float *widths = gsk_border_node_get_widths (node);
struct {
float w;
@@ -1818,52 +1794,48 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob *job,
const GskNglDrawVertex side_data[4][6] = {
/* Top */
{
- { { min_x, min_y }, { 0, 1 }, }, /* Upper left */
- { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
- { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+ { { min_x, min_y }, { 0, 1 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha } }, /* Upper left */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha } }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha } }, /* Upper right */
- { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, }, /* Lower right */
- { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
- { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+ { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha } }, /* Lower right */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha } }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha } }, /* Upper right */
},
/* Right */
{
- { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, }, /* Upper left */
- { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
- { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+ { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, { c[1].red, c[1].green, c[1].blue, c[1].alpha } }, /* Upper left */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, { c[1].red, c[1].green, c[1].blue, c[1].alpha } }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, { c[1].red, c[1].green, c[1].blue, c[1].alpha } }, /* Upper right */
- { { max_x, max_y }, { 1, 0 }, }, /* Lower right */
- { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
- { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+ { { max_x, max_y }, { 1, 0 }, { c[1].red, c[1].green, c[1].blue, c[1].alpha } }, /* Lower right */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, { c[1].red, c[1].green, c[1].blue, c[1].alpha } }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, { c[1].red, c[1].green, c[1].blue, c[1].alpha } }, /* Upper right */
},
/* Bottom */
{
- { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, }, /* Upper left */
- { { min_x, max_y }, { 0, 0 }, }, /* Lower left */
- { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
+ { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, { c[2].red, c[2].green, c[2].blue, c[2].alpha } }, /* Upper left */
+ { { min_x, max_y }, { 0, 0 }, { c[2].red, c[2].green, c[2].blue, c[2].alpha } }, /* Lower left */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, { c[2].red, c[2].green, c[2].blue, c[2].alpha } }, /* Upper right */
- { { max_x, max_y }, { 1, 0 }, }, /* Lower right */
- { { min_x , max_y }, { 0, 0 }, }, /* Lower left */
- { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
+ { { max_x, max_y }, { 1, 0 }, { c[2].red, c[2].green, c[2].blue, c[2].alpha } }, /* Lower right */
+ { { min_x , max_y }, { 0, 0 }, { c[2].red, c[2].green, c[2].blue, c[2].alpha } }, /* Lower left */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, { c[2].red, c[2].green, c[2].blue, c[2].alpha } }, /* Upper right */
},
/* Left */
{
- { { min_x, min_y }, { 0, 1 }, }, /* Upper left */
- { { min_x, max_y }, { 0, 0 }, }, /* Lower left */
- { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
+ { { min_x, min_y }, { 0, 1 }, { c[3].red, c[3].green, c[3].blue, c[3].alpha } }, /* Upper left */
+ { { min_x, max_y }, { 0, 0 }, { c[3].red, c[3].green, c[3].blue, c[3].alpha } }, /* Lower left */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, { c[3].red, c[3].green, c[3].blue, c[3].alpha } }, /* Upper right */
- { { min_x + sizes[3].w, max_y - sizes[3].h }, { 1, 0 }, }, /* Lower right */
- { { min_x, max_y }, { 0, 0 }, }, /* Lower left */
- { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
+ { { min_x + sizes[3].w, max_y - sizes[3].h }, { 1, 0 }, { c[3].red, c[3].green, c[3].blue, c[3].alpha } }, /* Lower right */
+ { { min_x, max_y }, { 0, 0 }, { c[3].red, c[3].green, c[3].blue, c[3].alpha } }, /* Lower left */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, { c[3].red, c[3].green, c[3].blue, c[3].alpha } }, /* Upper right */
}
};
- int indices[4] = { 0, 1, 2, 3 };
GskRoundedRect outline;
GskNglProgram *program;
- /* We sort them by color */
- sort_border_sides (colors, indices);
-
/* Prepare outline */
gsk_ngl_render_job_transform_rounded_rect (job, rounded_outline, &outline);
@@ -1881,16 +1853,12 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob *job,
{
GskNglDrawVertex *vertices;
- if (widths[indices[i]] <= 0)
+ if (widths[i] <= 0)
continue;
gsk_ngl_render_job_begin_draw (job, program);
- gsk_ngl_program_set_uniform4fv (job->current_program,
- UNIFORM_BORDER_COLOR, 0,
- 1,
- (const float *)&colors[indices[i]]);
vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
- memcpy (vertices, side_data[indices[i]], sizeof (GskNglDrawVertex) * GSK_NGL_N_VERTICES);
+ memcpy (vertices, side_data[i], sizeof (GskNglDrawVertex) * GSK_NGL_N_VERTICES);
gsk_ngl_render_job_end_draw (job);
}
}
@@ -2019,12 +1987,10 @@ gsk_ngl_render_job_visit_unblurred_inset_shadow_node (GskNglRenderJob *job,
gsk_ngl_render_job_transform_rounded_rect (job, outline, &transformed_outline);
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow));
+ gsk_ngl_render_job_set_color (job, gsk_inset_shadow_node_get_color (node));
gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_INSET_SHADOW_COLOR, 0,
- gsk_inset_shadow_node_get_color (node));
gsk_ngl_program_set_uniform1f (job->current_program,
UNIFORM_INSET_SHADOW_SPREAD, 0,
gsk_inset_shadow_node_get_spread (node));
@@ -2122,12 +2088,10 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob *job,
/* Actual inset shadow outline drawing */
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow));
+ gsk_ngl_render_job_set_color (job, gsk_inset_shadow_node_get_color (node));
gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_INSET_SHADOW_COLOR, 0,
- gsk_inset_shadow_node_get_color (node));
gsk_ngl_program_set_uniform1f (job->current_program,
UNIFORM_INSET_SHADOW_SPREAD, 0,
spread * MAX (scale_x, scale_y));
@@ -2231,12 +2195,10 @@ gsk_ngl_render_job_visit_unblurred_outset_shadow_node (GskNglRenderJob *job,
gsk_ngl_render_job_transform_rounded_rect (job, outline, &transformed_outline);
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, unblurred_outset_shadow));
+ gsk_ngl_render_job_set_color (job, gsk_outset_shadow_node_get_color (node));
gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_UNBLURRED_OUTSET_SHADOW_COLOR, 0,
- gsk_outset_shadow_node_get_color (node));
gsk_ngl_program_set_uniform1f (job->current_program,
UNIFORM_UNBLURRED_OUTSET_SHADOW_SPREAD, 0,
spread);
@@ -2387,9 +2349,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job,
/* Draw the outline using color program */
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_COLOR_COLOR, 0,
- &white);
+ gsk_ngl_render_job_set_color (job, &white);
gsk_ngl_render_job_draw (job, 0, 0, texture_width, texture_height);
gsk_ngl_render_job_end_draw (job);
@@ -2433,9 +2393,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job,
init_full_texture_region (&offscreen);
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, outset_shadow));
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_OUTSET_SHADOW_COLOR, 0,
- color);
+ gsk_ngl_render_job_set_color (job, color);
gsk_ngl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -2456,9 +2414,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job,
}
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, outset_shadow));
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_OUTSET_SHADOW_COLOR, 0,
- color);
+ gsk_ngl_render_job_set_color (job, color);
gsk_ngl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -2747,20 +2703,20 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
guint last_texture = 0;
GskNglDrawVertex *vertices;
guint used = 0;
+ GdkRGBA c;
if (num_glyphs == 0)
return;
- /* If the font has color glyphs, we don't need to recolor anything */
+ program = CHOOSE_PROGRAM (job, coloring);
+
+ /* If the font has color glyphs, we don't need to recolor anything.
+ * We tell the shader by setting the color to vec4(-1).
+ */
if (!force_color && gsk_text_node_has_color_glyphs (node))
- {
- program = CHOOSE_PROGRAM (job, blit);
- }
+ c = (GdkRGBA) { -1.f, -1.f, -1.f, -1.f };
else
- {
- program = CHOOSE_PROGRAM (job, coloring);
- gsk_ngl_program_set_uniform_color (program, UNIFORM_COLORING_COLOR, 0, color);
- }
+ c = *color;
lookup.font = (PangoFont *)font;
lookup.scale = (guint) (text_scale * 1024);
@@ -2835,31 +2791,55 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
vertices[base+0].position[1] = glyph_y;
vertices[base+0].uv[0] = tx;
vertices[base+0].uv[1] = ty;
+ vertices[base+0].color[0] = c.red;
+ vertices[base+0].color[1] = c.green;
+ vertices[base+0].color[2] = c.blue;
+ vertices[base+0].color[3] = c.alpha;
vertices[base+1].position[0] = glyph_x;
vertices[base+1].position[1] = glyph_y2;
vertices[base+1].uv[0] = tx;
vertices[base+1].uv[1] = ty2;
+ vertices[base+1].color[0] = c.red;
+ vertices[base+1].color[1] = c.green;
+ vertices[base+1].color[2] = c.blue;
+ vertices[base+1].color[3] = c.alpha;
vertices[base+2].position[0] = glyph_x2;
vertices[base+2].position[1] = glyph_y;
vertices[base+2].uv[0] = tx2;
vertices[base+2].uv[1] = ty;
+ vertices[base+2].color[0] = c.red;
+ vertices[base+2].color[1] = c.green;
+ vertices[base+2].color[2] = c.blue;
+ vertices[base+2].color[3] = c.alpha;
vertices[base+3].position[0] = glyph_x2;
vertices[base+3].position[1] = glyph_y2;
vertices[base+3].uv[0] = tx2;
vertices[base+3].uv[1] = ty2;
+ vertices[base+3].color[0] = c.red;
+ vertices[base+3].color[1] = c.green;
+ vertices[base+3].color[2] = c.blue;
+ vertices[base+3].color[3] = c.alpha;
vertices[base+4].position[0] = glyph_x;
vertices[base+4].position[1] = glyph_y2;
vertices[base+4].uv[0] = tx;
vertices[base+4].uv[1] = ty2;
+ vertices[base+4].color[0] = c.red;
+ vertices[base+4].color[1] = c.green;
+ vertices[base+4].color[2] = c.blue;
+ vertices[base+4].color[3] = c.alpha;
vertices[base+5].position[0] = glyph_x2;
vertices[base+5].position[1] = glyph_y;
vertices[base+5].uv[0] = tx2;
vertices[base+5].uv[1] = ty;
+ vertices[base+5].color[0] = c.red;
+ vertices[base+5].color[1] = c.green;
+ vertices[base+5].color[2] = c.blue;
+ vertices[base+5].color[3] = c.alpha;
batch->draw.vbo_count += GSK_NGL_N_VERTICES;
used++;
@@ -2952,14 +2932,12 @@ gsk_ngl_render_job_visit_shadow_node (GskNglRenderJob *job,
gsk_ngl_render_job_offset (job, dx, dy);
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring));
+ gsk_ngl_render_job_set_color (job, &shadow->color);
gsk_ngl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_COLORING_COLOR, 0,
- &shadow->color);
gsk_ngl_render_job_load_vertices_from_offscreen (job, &bounds, &offscreen);
gsk_ngl_render_job_end_draw (job);
gsk_ngl_render_job_offset (job, -dx, -dy);
@@ -3014,7 +2992,7 @@ gsk_ngl_render_job_visit_blur_node (GskNglRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
- gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y);
+ gsk_ngl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 1, 1, 0);
gsk_ngl_render_job_end_draw (job);
}
@@ -3123,9 +3101,7 @@ gsk_ngl_render_job_visit_gl_shader_node_fallback (GskNglRenderJob *job,
static const GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color));
- gsk_ngl_program_set_uniform_color (job->current_program,
- UNIFORM_COLOR_COLOR, 0,
- &pink);
+ gsk_ngl_render_job_set_color (job, &pink);
gsk_ngl_render_job_draw_rect (job, &node->bounds);
gsk_ngl_render_job_end_draw (job);
}
@@ -3317,7 +3293,6 @@ gsk_ngl_render_job_visit_texture_node (GskNglRenderJob *job,
for (guint i = 0; i < n_slices; i ++)
{
- GskNglDrawVertex *vertices;
const GskNglTextureSlice *slice = &slices[i];
float x1, x2, y1, y2;
@@ -3333,37 +3308,8 @@ gsk_ngl_render_job_visit_texture_node (GskNglRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
slice->texture_id);
- vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
- vertices[0].position[0] = x1;
- vertices[0].position[1] = y1;
- vertices[0].uv[0] = 0;
- vertices[0].uv[1] = 0;
-
- vertices[1].position[0] = x1;
- vertices[1].position[1] = y2;
- vertices[1].uv[0] = 0;
- vertices[1].uv[1] = 1;
-
- vertices[2].position[0] = x2;
- vertices[2].position[1] = y1;
- vertices[2].uv[0] = 1;
- vertices[2].uv[1] = 0;
-
- vertices[3].position[0] = x2;
- vertices[3].position[1] = y2;
- vertices[3].uv[0] = 1;
- vertices[3].uv[1] = 1;
-
- vertices[4].position[0] = x1;
- vertices[4].position[1] = y2;
- vertices[4].uv[0] = 0;
- vertices[4].uv[1] = 1;
-
- vertices[5].position[0] = x2;
- vertices[5].position[1] = y1;
- vertices[5].uv[0] = 1;
- vertices[5].uv[1] = 0;
+ gsk_ngl_render_job_draw_coords (job, x1, y1, x2, y2, 0, 0, 1, 1);
}
gsk_ngl_render_job_end_draw (job);
@@ -3900,6 +3846,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver,
job->viewport = *viewport;
gsk_ngl_render_job_set_alpha (job, 1.0);
+ gsk_ngl_render_job_set_color (job, &(GdkRGBA){ 0.f, 0.f, 0.f, 0.f });
gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL);
gsk_ngl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor));
diff --git a/gsk/ngl/gskngltypesprivate.h b/gsk/ngl/gskngltypesprivate.h
index aba6f2f4c9..dc76fb41f4 100644
--- a/gsk/ngl/gskngltypesprivate.h
+++ b/gsk/ngl/gskngltypesprivate.h
@@ -55,6 +55,7 @@ struct _GskNglDrawVertex
{
float position[2];
float uv[2];
+ float color[4];
};
G_END_DECLS
diff --git a/gsk/ngl/resources/blend.glsl b/gsk/ngl/resources/blend.glsl
new file mode 100644
index 0000000000..066c20179d
--- /dev/null
+++ b/gsk/ngl/resources/blend.glsl
@@ -0,0 +1,314 @@
+// VERTEX_SHADER:
+// blend.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// blend.glsl
+
+uniform int u_mode;
+uniform sampler2D u_source2;
+
+float
+combine (float source, float backdrop)
+{
+ return source + backdrop * (1.0 - source);
+}
+
+vec4
+composite (vec4 Cs, vec4 Cb, vec3 B)
+{
+ float ao = Cs.a + Cb.a * (1.0 - Cs.a);
+ vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao;
+ return vec4(Co, ao);
+}
+
+vec4
+normal (vec4 Cs, vec4 Cb)
+{
+ return composite (Cs, Cb, Cs.rgb);
+}
+
+vec4
+multiply (vec4 Cs, vec4 Cb)
+{
+ return composite (Cs, Cb, Cs.rgb * Cb.rgb);
+}
+
+vec4
+difference (vec4 Cs, vec4 Cb)
+{
+ return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
+}
+
+vec4
+screen (vec4 Cs, vec4 Cb)
+{
+ return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
+}
+
+float
+hard_light (float source, float backdrop)
+{
+ if (source <= 0.5)
+ return 2.0 * backdrop * source;
+ else
+ return 2.0 * (backdrop + source - backdrop * source) - 1.0;
+}
+
+vec4
+hard_light (vec4 Cs, vec4 Cb)
+{
+ vec3 B = vec3 (hard_light (Cs.r, Cb.r),
+ hard_light (Cs.g, Cb.g),
+ hard_light (Cs.b, Cb.b));
+ return composite (Cs, Cb, B);
+}
+
+float
+soft_light (float source, float backdrop)
+{
+ float db;
+
+ if (backdrop <= 0.25)
+ db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop;
+ else
+ db = sqrt (backdrop);
+
+ if (source <= 0.5)
+ return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop);
+ else
+ return backdrop + (2.0 * source - 1.0) * (db - backdrop);
+}
+
+vec4
+soft_light (vec4 Cs, vec4 Cb)
+{
+ vec3 B = vec3 (soft_light (Cs.r, Cb.r),
+ soft_light (Cs.g, Cb.g),
+ soft_light (Cs.b, Cb.b));
+ return composite (Cs, Cb, B);
+}
+
+vec4
+overlay (vec4 Cs, vec4 Cb)
+{
+ vec3 B = vec3 (hard_light (Cb.r, Cs.r),
+ hard_light (Cb.g, Cs.g),
+ hard_light (Cb.b, Cs.b));
+ return composite (Cs, Cb, B);
+}
+
+vec4
+darken (vec4 Cs, vec4 Cb)
+{
+ vec3 B = min (Cs.rgb, Cb.rgb);
+ return composite (Cs, Cb, B);
+}
+
+vec4
+lighten (vec4 Cs, vec4 Cb)
+{
+ vec3 B = max (Cs.rgb, Cb.rgb);
+ return composite (Cs, Cb, B);
+}
+
+float
+color_dodge (float source, float backdrop)
+{
+ return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
+}
+
+vec4
+color_dodge (vec4 Cs, vec4 Cb)
+{
+ vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
+ color_dodge (Cs.g, Cb.g),
+ color_dodge (Cs.b, Cb.b));
+ return composite (Cs, Cb, B);
+}
+
+
+float
+color_burn (float source, float backdrop)
+{
+ return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
+}
+
+vec4
+color_burn (vec4 Cs, vec4 Cb)
+{
+ vec3 B = vec3 (color_burn (Cs.r, Cb.r),
+ color_burn (Cs.g, Cb.g),
+ color_burn (Cs.b, Cb.b));
+ return composite (Cs, Cb, B);
+}
+
+vec4
+exclusion (vec4 Cs, vec4 Cb)
+{
+ vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
+ return composite (Cs, Cb, B);
+}
+
+float
+lum (vec3 c)
+{
+ return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
+}
+
+vec3
+clip_color (vec3 c)
+{
+ float l = lum (c);
+ float n = min (c.r, min (c.g, c.b));
+ float x = max (c.r, max (c.g, c.b));
+ if (n < 0.0) c = l + (((c - l) * l) / (l - n));
+ if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l));
+ return c;
+}
+
+vec3
+set_lum (vec3 c, float l)
+{
+ float d = l - lum (c);
+ return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
+}
+
+float
+sat (vec3 c)
+{
+ return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
+}
+
+vec3
+set_sat (vec3 c, float s)
+{
+ float cmin = min (c.r, min (c.g, c.b));
+ float cmax = max (c.r, max (c.g, c.b));
+ vec3 res;
+
+ if (cmax == cmin)
+ res = vec3 (0, 0, 0);
+ else
+ {
+ if (c.r == cmax)
+ {
+ if (c.g == cmin)
+ {
+ res.b = ((c.b - cmin) * s) / (cmax - cmin);
+ res.g = 0.0;
+ }
+ else
+ {
+ res.g = ((c.g - cmin) * s) / (cmax - cmin);
+ res.b = 0.0;
+ }
+ res.r = s;
+ }
+ else if (c.g == cmax)
+ {
+ if (c.r == cmin)
+ {
+ res.b = ((c.b - cmin) * s) / (cmax - cmin);
+ res.r = 0.0;
+ }
+ else
+ {
+ res.r = ((c.r - cmin) * s) / (cmax - cmin);
+ res.b = 0.0;
+ }
+ res.g = s;
+ }
+ else
+ {
+ if (c.r == cmin)
+ {
+ res.g = ((c.g - cmin) * s) / (cmax - cmin);
+ res.r = 0.0;
+ }
+ else
+ {
+ res.r = ((c.r - cmin) * s) / (cmax - cmin);
+ res.g = 0.0;
+ }
+ res.b = s;
+ }
+ }
+ return res;
+}
+
+vec4
+color (vec4 Cs, vec4 Cb)
+{
+ vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
+ return composite (Cs, Cb, B);
+}
+
+vec4
+hue (vec4 Cs, vec4 Cb)
+{
+ vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
+ return composite (Cs, Cb, B);
+}
+
+vec4
+saturation (vec4 Cs, vec4 Cb)
+{
+ vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
+ return composite (Cs, Cb, B);
+}
+
+vec4
+luminosity (vec4 Cs, vec4 Cb)
+{
+ vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
+ return composite (Cs, Cb, B);
+}
+
+void main() {
+ vec4 bottom_color = GskTexture(u_source, vUv);
+ vec4 top_color = GskTexture(u_source2, vUv);
+
+ vec4 result;
+ if (u_mode == 0)
+ result = normal(top_color, bottom_color);
+ else if (u_mode == 1)
+ result = multiply(top_color, bottom_color);
+ else if (u_mode == 2)
+ result = screen(top_color, bottom_color);
+ else if (u_mode == 3)
+ result = overlay(top_color, bottom_color);
+ else if (u_mode == 4)
+ result = darken(top_color, bottom_color);
+ else if (u_mode == 5)
+ result = lighten(top_color, bottom_color);
+ else if (u_mode == 6)
+ result = color_dodge(top_color, bottom_color);
+ else if (u_mode == 7)
+ result = color_burn(top_color, bottom_color);
+ else if (u_mode == 8)
+ result = hard_light(top_color, bottom_color);
+ else if (u_mode == 9)
+ result = soft_light(top_color, bottom_color);
+ else if (u_mode == 10)
+ result = difference(top_color, bottom_color);
+ else if (u_mode == 11)
+ result = exclusion(top_color, bottom_color);
+ else if (u_mode == 12)
+ result = color(top_color, bottom_color);
+ else if (u_mode == 13)
+ result = hue(top_color, bottom_color);
+ else if (u_mode == 14)
+ result = saturation(top_color, bottom_color);
+ else if (u_mode == 15)
+ result = luminosity(top_color, bottom_color);
+ else
+ discard;
+
+ gskSetOutputColor(result * u_alpha);
+}
diff --git a/gsk/ngl/resources/blit.glsl b/gsk/ngl/resources/blit.glsl
new file mode 100644
index 0000000000..c232be2bfd
--- /dev/null
+++ b/gsk/ngl/resources/blit.glsl
@@ -0,0 +1,17 @@
+// VERTEX_SHADER:
+// blit.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// blit.glsl
+
+void main() {
+ vec4 diffuse = GskTexture(u_source, vUv);
+
+ gskSetOutputColor(diffuse * u_alpha);
+}
diff --git a/gsk/ngl/resources/blur.glsl b/gsk/ngl/resources/blur.glsl
new file mode 100644
index 0000000000..7e7c1c2518
--- /dev/null
+++ b/gsk/ngl/resources/blur.glsl
@@ -0,0 +1,59 @@
+// VERTEX_SHADER:
+// blur.glsl
+
+uniform float u_blur_radius;
+uniform vec2 u_blur_size;
+uniform vec2 u_blur_dir;
+
+_OUT_ vec2 pixel_step;
+_OUT_ float pixels_per_side;
+_OUT_ vec3 initial_gaussian;
+
+const float PI = 3.14159265;
+const float RADIUS_MULTIPLIER = 2.0;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+
+ pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir;
+ pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0);
+
+ float sigma = u_blur_radius / 2.0; // *shrug*
+ initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
+ initial_gaussian.y = exp(-0.5 / (sigma * sigma));
+ initial_gaussian.z = initial_gaussian.y * initial_gaussian.y;
+}
+
+// FRAGMENT_SHADER:
+// blur.glsl
+
+_IN_ vec2 pixel_step;
+_IN_ float pixels_per_side;
+_IN_ vec3 initial_gaussian;
+
+// blur_radius 0 is NOT supported and MUST be caught before.
+
+// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
+void main() {
+ vec3 incrementalGaussian = initial_gaussian;
+
+ float coefficientSum = 0.0;
+ vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x;
+ coefficientSum += incrementalGaussian.x;
+ incrementalGaussian.xy *= incrementalGaussian.yz;
+
+ vec2 p = pixel_step;
+ for (int i = 1; i <= int(pixels_per_side); i++) {
+ sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x;
+ sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x;
+
+ coefficientSum += 2.0 * incrementalGaussian.x;
+ incrementalGaussian.xy *= incrementalGaussian.yz;
+
+ p += pixel_step;
+ }
+
+ gskSetOutputColor(sum / coefficientSum);
+}
diff --git a/gsk/ngl/resources/border.glsl b/gsk/ngl/resources/border.glsl
new file mode 100644
index 0000000000..a9c04556a4
--- /dev/null
+++ b/gsk/ngl/resources/border.glsl
@@ -0,0 +1,43 @@
+// VERTEX_SHADER:
+// border.glsl
+
+uniform vec4 u_widths;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ final_color = gsk_premultiply(aColor) * u_alpha;
+
+ GskRoundedRect outside = gsk_create_rect(u_outline_rect);
+ GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
+
+ gsk_rounded_rect_transform(outside, u_modelview);
+ gsk_rounded_rect_transform(inside, u_modelview);
+
+ gsk_rounded_rect_encode(outside, transformed_outside_outline);
+ gsk_rounded_rect_encode(inside, transformed_inside_outline);
+}
+
+// FRAGMENT_SHADER:
+// border.glsl
+
+uniform vec4[3] u_outline_rect;
+
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+ vec2 frag = gsk_get_frag_coord();
+
+ float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
+ gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
+ 0.0, 1.0);
+
+ gskSetOutputColor(final_color * alpha);
+}
diff --git a/gsk/ngl/resources/color.glsl b/gsk/ngl/resources/color.glsl
new file mode 100644
index 0000000000..670b9979a2
--- /dev/null
+++ b/gsk/ngl/resources/color.glsl
@@ -0,0 +1,20 @@
+// VERTEX_SHADER:
+// color.glsl
+
+_OUT_ vec4 final_color;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ final_color = gsk_premultiply(aColor) * u_alpha;
+}
+
+// FRAGMENT_SHADER:
+// color.glsl
+
+_IN_ vec4 final_color;
+
+void main() {
+ gskSetOutputColor(final_color);
+}
+
diff --git a/gsk/ngl/resources/color_matrix.glsl b/gsk/ngl/resources/color_matrix.glsl
new file mode 100644
index 0000000000..44dcf9a044
--- /dev/null
+++ b/gsk/ngl/resources/color_matrix.glsl
@@ -0,0 +1,29 @@
+// VERTEX_SHADER:
+// color_matrix.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// color_matrix.glsl
+
+uniform mat4 u_color_matrix;
+uniform vec4 u_color_offset;
+
+void main() {
+ vec4 color = GskTexture(u_source, vUv);
+
+ // Un-premultilpy
+ if (color.a != 0.0)
+ color.rgb /= color.a;
+
+ color = u_color_matrix * color + u_color_offset;
+ color = clamp(color, 0.0, 1.0);
+
+ color.rgb *= color.a;
+
+ gskSetOutputColor(color * u_alpha);
+}
diff --git a/gsk/ngl/resources/coloring.glsl b/gsk/ngl/resources/coloring.glsl
new file mode 100644
index 0000000000..69b21c6e2e
--- /dev/null
+++ b/gsk/ngl/resources/coloring.glsl
@@ -0,0 +1,36 @@
+// VERTEX_SHADER:
+// coloring.glsl
+
+_OUT_ vec4 final_color;
+flat _OUT_ int use_color;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+
+ // We use this shader for both plain glyphs (used as mask)
+ // and color glpyhs (used as source). The renderer sets
+ // aColor to vec4(-1) for color glyhs.
+ if (distance(aColor, vec4(-1)) < 0.001)
+ use_color = 0;
+ else
+ use_color = 1;
+
+ final_color = gsk_premultiply(aColor) * u_alpha;
+}
+
+// FRAGMENT_SHADER:
+// coloring.glsl
+
+_IN_ vec4 final_color;
+flat _IN_ int use_color;
+
+void main() {
+ vec4 diffuse = GskTexture(u_source, vUv);
+
+ if (use_color == 1)
+ gskSetOutputColor(final_color * diffuse.a);
+ else
+ gskSetOutputColor(diffuse * u_alpha);
+}
diff --git a/gsk/ngl/resources/conic_gradient.glsl b/gsk/ngl/resources/conic_gradient.glsl
new file mode 100644
index 0000000000..afb427bb15
--- /dev/null
+++ b/gsk/ngl/resources/conic_gradient.glsl
@@ -0,0 +1,76 @@
+// VERTEX_SHADER
+// conic_gradient.glsl
+
+uniform vec4 u_geometry;
+
+_NOPERSPECTIVE_ _OUT_ vec2 coord;
+
+void main() {
+ gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+ vec2 mv0 = u_modelview[0].xy;
+ vec2 mv1 = u_modelview[1].xy;
+ vec2 offset = aPosition - u_geometry.xy;
+
+ coord = vec2(dot(mv0, offset), dot(mv1, offset));
+}
+
+// FRAGMENT_SHADER:
+// conic_gradient.glsl
+
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops; // Why? Because it works like this.
+#endif
+
+uniform vec4 u_geometry;
+uniform float u_color_stops[6 * 5];
+
+_NOPERSPECTIVE_ _IN_ vec2 coord;
+
+float get_offset(int index) {
+ return u_color_stops[5 * index];
+}
+
+vec4 get_color(int index) {
+ int base = 5 * index + 1;
+
+ return vec4(u_color_stops[base],
+ u_color_stops[base + 1],
+ u_color_stops[base + 2],
+ u_color_stops[base + 3]);
+}
+
+void main() {
+ // direction of point in range [-PI, PI]
+ vec2 pos = floor(coord);
+ float angle = atan(pos.y, pos.x);
+
+ // fract() does the modulo here, so now we have progress
+ // into the current conic
+ float offset = fract(angle * u_geometry.z + u_geometry.w);
+
+ if (offset < get_offset(0)) {
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+ return;
+ }
+
+ int n = u_num_color_stops - 1;
+ for (int i = 0; i < n; i++) {
+ float curr_offset = get_offset(i);
+ float next_offset = get_offset(i + 1);
+
+ if (offset >= curr_offset && offset < next_offset) {
+ float f = (offset - curr_offset) / (next_offset - curr_offset);
+ vec4 curr_color = gsk_premultiply(get_color(i));
+ vec4 next_color = gsk_premultiply(get_color(i + 1));
+ vec4 color = mix(curr_color, next_color, f);
+
+ gskSetOutputColor(color * u_alpha);
+ return;
+ }
+ }
+
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+}
diff --git a/gsk/ngl/resources/cross_fade.glsl b/gsk/ngl/resources/cross_fade.glsl
new file mode 100644
index 0000000000..e61af597e9
--- /dev/null
+++ b/gsk/ngl/resources/cross_fade.glsl
@@ -0,0 +1,24 @@
+// VERTEX_SHADER:
+// cross_fade.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// cross_fade.glsl
+
+uniform float u_progress;
+uniform sampler2D u_source2;
+
+void main() {
+ vec4 source1 = GskTexture(u_source, vUv); // start child
+ vec4 source2 = GskTexture(u_source2, vUv); // end child
+
+ float p_start = (1.0 - u_progress) * u_alpha;
+ float p_end = u_progress * u_alpha;
+ vec4 color = (p_start * source1) + (p_end * source2);
+ gskSetOutputColor(color);
+}
diff --git a/gsk/ngl/resources/custom.glsl b/gsk/ngl/resources/custom.glsl
new file mode 100644
index 0000000000..6f91df6cf4
--- /dev/null
+++ b/gsk/ngl/resources/custom.glsl
@@ -0,0 +1,25 @@
+// VERTEX_SHADER:
+// custom.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// custom.glsl
+
+// The shader supplies:
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv);
+
+uniform vec2 u_size;
+uniform sampler2D u_source2;
+uniform sampler2D u_source3;
+uniform sampler2D u_source4;
+
+void main() {
+ vec4 fragColor;
+ vec2 fragCoord = vec2(vUv.x * u_size.x, (1.0-vUv.y) * u_size.y);
+ mainImage(fragColor, fragCoord, u_size, vUv);
+ gskSetOutputColor(fragColor);
+}
diff --git a/gsk/ngl/resources/inset_shadow.glsl b/gsk/ngl/resources/inset_shadow.glsl
new file mode 100644
index 0000000000..1c3c955035
--- /dev/null
+++ b/gsk/ngl/resources/inset_shadow.glsl
@@ -0,0 +1,44 @@
+// VERTEX_SHADER:
+// inset_shadow.glsl
+
+uniform float u_spread;
+uniform vec2 u_offset;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ final_color = gsk_premultiply(aColor) * u_alpha;
+
+ GskRoundedRect outside = gsk_create_rect(u_outline_rect);
+ GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread));
+
+ gsk_rounded_rect_offset(inside, u_offset);
+
+ gsk_rounded_rect_transform(outside, u_modelview);
+ gsk_rounded_rect_transform(inside, u_modelview);
+
+ gsk_rounded_rect_encode(outside, transformed_outside_outline);
+ gsk_rounded_rect_encode(inside, transformed_inside_outline);
+}
+
+// FRAGMENT_SHADER:
+// inset_shadow.glsl
+
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+ vec2 frag = gsk_get_frag_coord();
+
+ float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
+ gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
+ 0.0, 1.0);
+
+ gskSetOutputColor(final_color * alpha);
+}
diff --git a/gsk/ngl/resources/linear_gradient.glsl b/gsk/ngl/resources/linear_gradient.glsl
new file mode 100644
index 0000000000..1a2f2675e0
--- /dev/null
+++ b/gsk/ngl/resources/linear_gradient.glsl
@@ -0,0 +1,98 @@
+// VERTEX_SHADER
+// linear_gradient.glsl
+uniform vec4 u_points;
+
+_NOPERSPECTIVE_ _OUT_ vec4 info;
+
+void main() {
+ gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+ vec2 mv0 = u_modelview[0].xy;
+ vec2 mv1 = u_modelview[1].xy;
+ vec2 offset = aPosition - u_points.xy;
+ vec2 coord = vec2(dot(mv0, offset),
+ dot(mv1, offset));
+
+ // Original equation:
+ // VS | maxDist = length(end - start);
+ // VS | gradient = end - start;
+ // VS | gradientLength = length(gradient);
+ // FS | pos = frag_coord - start
+ // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient
+ // FS | offset = length(proj) / maxDist
+
+ // Simplified formula derivation:
+ // 1. Notice that maxDist = gradientLength:
+ // offset = length(proj) / gradientLength
+ // 2. Let gnorm = gradient / gradientLength, then:
+ // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) =
+ // = dot(gnorm, pos) * gnorm
+ // 3. Since gnorm is unit length then:
+ // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos)
+ // 4. We can avoid the FS division by passing a scaled pos from the VS:
+ // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength)
+ // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL
+ vec2 gradient = vec2(dot(mv0, u_points.zw),
+ dot(mv1, u_points.zw));
+ float rcp_gradient_length = inversesqrt(dot(gradient, gradient));
+
+ info = rcp_gradient_length * vec4(coord, gradient);
+}
+
+// FRAGMENT_SHADER:
+// linear_gradient.glsl
+
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops; // Why? Because it works like this.
+#endif
+
+uniform float u_color_stops[6 * 5];
+uniform bool u_repeat;
+
+_NOPERSPECTIVE_ _IN_ vec4 info;
+
+float get_offset(int index) {
+ return u_color_stops[5 * index];
+}
+
+vec4 get_color(int index) {
+ int base = 5 * index + 1;
+
+ return vec4(u_color_stops[base],
+ u_color_stops[base + 1],
+ u_color_stops[base + 2],
+ u_color_stops[base + 3]);
+}
+
+void main() {
+ float offset = dot(info.xy, info.zw);
+
+ if (u_repeat) {
+ offset = fract(offset);
+ }
+
+ if (offset < get_offset(0)) {
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+ return;
+ }
+
+ int n = u_num_color_stops - 1;
+ for (int i = 0; i < n; i++) {
+ float curr_offset = get_offset(i);
+ float next_offset = get_offset(i + 1);
+
+ if (offset >= curr_offset && offset < next_offset) {
+ float f = (offset - curr_offset) / (next_offset - curr_offset);
+ vec4 curr_color = gsk_premultiply(get_color(i));
+ vec4 next_color = gsk_premultiply(get_color(i + 1));
+ vec4 color = mix(curr_color, next_color, f);
+
+ gskSetOutputColor(color * u_alpha);
+ return;
+ }
+ }
+
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+}
diff --git a/gsk/ngl/resources/outset_shadow.glsl b/gsk/ngl/resources/outset_shadow.glsl
new file mode 100644
index 0000000000..427aee956c
--- /dev/null
+++ b/gsk/ngl/resources/outset_shadow.glsl
@@ -0,0 +1,36 @@
+// VERTEX_SHADER:
+// outset_shadow.glsl
+
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+
+ final_color = gsk_premultiply(aColor) * u_alpha;
+
+ GskRoundedRect outline = gsk_create_rect(u_outline_rect);
+ gsk_rounded_rect_transform(outline, u_modelview);
+ gsk_rounded_rect_encode(outline, transformed_outline);
+}
+
+// FRAGMENT_SHADER:
+// outset_shadow.glsl
+
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
+
+void main() {
+ vec2 frag = gsk_get_frag_coord();
+ float alpha = GskTexture(u_source, vUv).a;
+
+ alpha *= (1.0 - clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0));
+
+ vec4 color = final_color * alpha;
+
+ gskSetOutputColor(color);
+}
diff --git a/gsk/ngl/resources/preamble.fs.glsl b/gsk/ngl/resources/preamble.fs.glsl
new file mode 100644
index 0000000000..e715d2526d
--- /dev/null
+++ b/gsk/ngl/resources/preamble.fs.glsl
@@ -0,0 +1,138 @@
+uniform sampler2D u_source;
+uniform mat4 u_projection;
+uniform mat4 u_modelview;
+uniform float u_alpha;
+uniform vec4 u_viewport;
+uniform vec4[3] u_clip_rect;
+
+#if defined(GSK_LEGACY)
+_OUT_ vec4 outputColor;
+#elif !defined(GSK_GLES)
+_OUT_ vec4 outputColor;
+#endif
+
+_IN_ vec2 vUv;
+
+
+GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r)
+{
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+ return GskRoundedRect(r[0], r[1], r[2]);
+#else
+ return r;
+#endif
+}
+
+float
+gsk_ellipsis_dist (vec2 p, vec2 radius)
+{
+ if (radius == vec2(0, 0))
+ return 0.0;
+
+ vec2 p0 = p / radius;
+ vec2 p1 = 2.0 * p0 / radius;
+
+ return (dot(p0, p0) - 1.0) / length (p1);
+}
+
+float
+gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
+{
+ float d = gsk_ellipsis_dist (point - center, radius);
+ return clamp (0.5 - d, 0.0, 1.0);
+}
+
+float
+gsk_rounded_rect_coverage (GskRoundedRect r, vec2 p)
+{
+ if (p.x < r.bounds.x || p.y < r.bounds.y ||
+ p.x >= r.bounds.z || p.y >= r.bounds.w)
+ return 0.0;
+
+ vec2 ref_tl = r.corner_points1.xy;
+ vec2 ref_tr = r.corner_points1.zw;
+ vec2 ref_br = r.corner_points2.xy;
+ vec2 ref_bl = r.corner_points2.zw;
+
+ if (p.x >= ref_tl.x && p.x >= ref_bl.x &&
+ p.x <= ref_tr.x && p.x <= ref_br.x)
+ return 1.0;
+
+ if (p.y >= ref_tl.y && p.y >= ref_tr.y &&
+ p.y <= ref_bl.y && p.y <= ref_br.y)
+ return 1.0;
+
+ vec2 rad_tl = r.corner_points1.xy - r.bounds.xy;
+ vec2 rad_tr = r.corner_points1.zw - r.bounds.zy;
+ vec2 rad_br = r.corner_points2.xy - r.bounds.zw;
+ vec2 rad_bl = r.corner_points2.zw - r.bounds.xw;
+
+ float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl);
+ float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr);
+ float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br);
+ float d_bl = gsk_ellipsis_coverage(p, ref_bl, rad_bl);
+
+ vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
+
+ bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
+ p.x > ref_tr.x && p.y < ref_tr.y,
+ p.x > ref_br.x && p.y > ref_br.y,
+ p.x < ref_bl.x && p.y > ref_bl.y);
+
+ return 1.0 - dot(vec4(is_out), corner_coverages);
+}
+
+float
+gsk_rect_coverage (vec4 r, vec2 p)
+{
+ if (p.x < r.x || p.y < r.y ||
+ p.x >= r.z || p.y >= r.w)
+ return 0.0;
+
+ return 1.0;
+}
+
+vec4 GskTexture(sampler2D sampler, vec2 texCoords) {
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+ return texture2D(sampler, texCoords);
+#else
+ return texture(sampler, texCoords);
+#endif
+}
+
+#ifdef GSK_GL3
+layout(origin_upper_left) in vec4 gl_FragCoord;
+#endif
+
+vec2 gsk_get_frag_coord() {
+ vec2 fc = gl_FragCoord.xy;
+
+#ifdef GSK_GL3
+ fc += u_viewport.xy;
+#else
+ fc.x += u_viewport.x;
+ fc.y = (u_viewport.y + u_viewport.w) - fc.y;
+#endif
+
+ return fc;
+}
+
+void gskSetOutputColor(vec4 color) {
+ vec4 result;
+
+#if defined(NO_CLIP)
+ result = color;
+#elif defined(RECT_CLIP)
+ result = color * gsk_rect_coverage(gsk_get_bounds(u_clip_rect),
+ gsk_get_frag_coord());
+#else
+ result = color * gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect),
+ gsk_get_frag_coord());
+#endif
+
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+ gl_FragColor = result;
+#else
+ outputColor = result;
+#endif
+}
diff --git a/gsk/ngl/resources/preamble.glsl b/gsk/ngl/resources/preamble.glsl
new file mode 100644
index 0000000000..8bc007ba67
--- /dev/null
+++ b/gsk/ngl/resources/preamble.glsl
@@ -0,0 +1,57 @@
+#ifndef GSK_LEGACY
+precision highp float;
+#endif
+
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+#define _OUT_ varying
+#define _IN_ varying
+#define _NOPERSPECTIVE_
+#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3]
+#else
+#define _OUT_ out
+#define _IN_ in
+#define _NOPERSPECTIVE_ noperspective
+#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect
+#endif
+
+
+struct GskRoundedRect
+{
+ vec4 bounds; // Top left and bottom right
+ // Look, arrays can't be in structs if you want to return the struct
+ // from a function in gles or whatever. Just kill me.
+ vec4 corner_points1; // xy = top left, zw = top right
+ vec4 corner_points2; // xy = bottom right, zw = bottom left
+};
+
+// Transform from a C GskRoundedRect to what we need.
+GskRoundedRect
+gsk_create_rect(vec4[3] data)
+{
+ vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw);
+
+ vec4 corner_points1 = vec4(bounds.xy + data[1].xy,
+ bounds.zy + vec2(data[1].zw * vec2(-1, 1)));
+ vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)),
+ bounds.xw + vec2(data[2].zw * vec2(1, -1)));
+
+ return GskRoundedRect(bounds, corner_points1, corner_points2);
+}
+
+vec4
+gsk_get_bounds(vec4[3] data)
+{
+ return vec4(data[0].xy, data[0].xy + data[0].zw);
+}
+
+vec4 gsk_premultiply(vec4 c) {
+ return vec4(c.rgb * c.a, c.a);
+}
+
+vec4 gsk_scaled_premultiply(vec4 c, float s) {
+ // Fast version of gsk_premultiply(c) * s
+ // 4 muls instead of 7
+ float a = s * c.a;
+
+ return vec4(c.rgb * a, a);
+}
diff --git a/gsk/ngl/resources/preamble.vs.glsl b/gsk/ngl/resources/preamble.vs.glsl
new file mode 100644
index 0000000000..a549ff6ded
--- /dev/null
+++ b/gsk/ngl/resources/preamble.vs.glsl
@@ -0,0 +1,71 @@
+uniform mat4 u_projection;
+uniform mat4 u_modelview;
+uniform float u_alpha;
+
+#if defined(GSK_GLES) || defined(GSK_LEGACY)
+attribute vec2 aPosition;
+attribute vec2 aUv;
+attribute vec4 aColor;
+_OUT_ vec2 vUv;
+#else
+_IN_ vec2 aPosition;
+_IN_ vec2 aUv;
+_IN_ vec4 aColor;
+_OUT_ vec2 vUv;
+#endif
+
+// amount is: top, right, bottom, left
+GskRoundedRect
+gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount)
+{
+ vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
+ vec4 new_corner_points1 = r.corner_points1;
+ vec4 new_corner_points2 = r.corner_points2;
+
+ if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy;
+ if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy;
+ if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw;
+ if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw;
+
+ return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2);
+}
+
+void
+gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset)
+{
+ r.bounds.xy += offset;
+ r.bounds.zw += offset;
+ r.corner_points1.xy += offset;
+ r.corner_points1.zw += offset;
+ r.corner_points2.xy += offset;
+ r.corner_points2.zw += offset;
+}
+
+void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat)
+{
+ r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy;
+ r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy;
+
+ r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy;
+ r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy;
+
+ r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy;
+ r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy;
+}
+
+#if defined(GSK_LEGACY)
+// Can't have out or inout array parameters...
+#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2;
+#else
+void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r)
+{
+#if defined(GSK_GLES)
+ out_r[0] = r.bounds;
+ out_r[1] = r.corner_points1;
+ out_r[2] = r.corner_points2;
+#else
+ out_r = r;
+#endif
+}
+
+#endif
diff --git a/gsk/ngl/resources/radial_gradient.glsl b/gsk/ngl/resources/radial_gradient.glsl
new file mode 100644
index 0000000000..e8b57ef635
--- /dev/null
+++ b/gsk/ngl/resources/radial_gradient.glsl
@@ -0,0 +1,78 @@
+// VERTEX_SHADER
+// radial_gradient.glsl
+
+uniform vec4 u_geometry;
+
+_NOPERSPECTIVE_ _OUT_ vec2 coord;
+
+void main() {
+ gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+ vec2 mv0 = u_modelview[0].xy;
+ vec2 mv1 = u_modelview[1].xy;
+ vec2 offset = aPosition - u_geometry.xy;
+ vec2 dir = vec2(dot(mv0, offset),
+ dot(mv1, offset));
+
+ coord = dir * u_geometry.zw;
+}
+
+// FRAGMENT_SHADER:
+// radial_gradient.glsl
+
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops;
+#endif
+
+uniform bool u_repeat;
+uniform vec2 u_range;
+uniform float u_color_stops[6 * 5];
+
+_NOPERSPECTIVE_ _IN_ vec2 coord;
+
+float get_offset(int index) {
+ return u_color_stops[5 * index];
+}
+
+vec4 get_color(int index) {
+ int base = 5 * index + 1;
+
+ return vec4(u_color_stops[base],
+ u_color_stops[base + 1],
+ u_color_stops[base + 2],
+ u_color_stops[base + 3]);
+}
+
+void main() {
+ // Reverse scale
+ float offset = length(coord) * u_range.x + u_range.y;
+
+ if (u_repeat) {
+ offset = fract(offset);
+ }
+
+ if (offset < get_offset(0)) {
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+ return;
+ }
+
+ int n = u_num_color_stops - 1;
+ for (int i = 0; i < n; i++) {
+ float curr_offset = get_offset(i);
+ float next_offset = get_offset(i + 1);
+
+ if (offset >= curr_offset && offset < next_offset) {
+ float f = (offset - curr_offset) / (next_offset - curr_offset);
+ vec4 curr_color = gsk_premultiply(get_color(i));
+ vec4 next_color = gsk_premultiply(get_color(i + 1));
+ vec4 color = mix(curr_color, next_color, f);
+
+ gskSetOutputColor(color * u_alpha);
+ return;
+ }
+ }
+
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
+}
diff --git a/gsk/ngl/resources/repeat.glsl b/gsk/ngl/resources/repeat.glsl
new file mode 100644
index 0000000000..5d39603396
--- /dev/null
+++ b/gsk/ngl/resources/repeat.glsl
@@ -0,0 +1,44 @@
+// VERTEX_SHADER:
+// repeat.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// repeat.glsl
+
+uniform vec4 u_child_bounds;
+uniform vec4 u_texture_rect;
+
+float wrap(float f, float wrap_for) {
+ return mod(f, wrap_for);
+}
+
+/* We get the texture coordinates via vUv,
+ * but that might be on a texture atlas, so we need to do the
+ * wrapping ourselves.
+ */
+void main() {
+
+ /* We map the texture coordinate to [1;0], then wrap it and scale the result again */
+
+ float tw = u_texture_rect.z - u_texture_rect.x;
+ float th = u_texture_rect.w - u_texture_rect.y;
+
+ float mapped_x = (vUv.x - u_texture_rect.x) / tw;
+ float mapped_y = (vUv.y - u_texture_rect.y) / th;
+
+ float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0);
+ float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0);
+
+ vec2 tp;
+ tp.x = u_texture_rect.x + (wrapped_x * tw);
+ tp.y = u_texture_rect.y + (wrapped_y * th);
+
+ vec4 diffuse = GskTexture(u_source, tp);
+
+ gskSetOutputColor(diffuse * u_alpha);
+}
diff --git a/gsk/ngl/resources/unblurred_outset_shadow.glsl b/gsk/ngl/resources/unblurred_outset_shadow.glsl
new file mode 100644
index 0000000000..305cc5f1e2
--- /dev/null
+++ b/gsk/ngl/resources/unblurred_outset_shadow.glsl
@@ -0,0 +1,44 @@
+// VERTEX_SHADER:
+// unblurred_outset_shadow.glsl
+
+uniform float u_spread;
+uniform vec2 u_offset;
+uniform vec4[3] u_outline_rect;
+
+_OUT_ vec4 final_color;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ final_color = gsk_premultiply(aColor) * u_alpha;
+
+ GskRoundedRect inside = gsk_create_rect(u_outline_rect);
+ GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread));
+
+ gsk_rounded_rect_offset(outside, u_offset);
+
+ gsk_rounded_rect_transform(outside, u_modelview);
+ gsk_rounded_rect_transform(inside, u_modelview);
+
+ gsk_rounded_rect_encode(outside, transformed_outside_outline);
+ gsk_rounded_rect_encode(inside, transformed_inside_outline);
+}
+
+// FRAGMENT_SHADER:
+// unblurred_outset_shadow.glsl
+_IN_ vec4 final_color;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
+_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
+
+void main() {
+ vec2 frag = gsk_get_frag_coord();
+
+ float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
+ gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
+ 0.0, 1.0);
+
+ gskSetOutputColor(final_color * alpha);
+}
+