[gtk/matthiasc/gltransition-demo: 3/3] Add another shader node demo




commit 50725b67ac0037c00949dc92d7ed4d23a6f85c3a
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Sep 21 22:16:54 2020 -0400

    Add another shader node demo
    
    This one does stack-like transitions, using
    some examples from gl-transitions.com.

 demos/gtk-demo/demo.gresource.xml |   9 +
 demos/gtk-demo/gltransition.c     | 250 ++++++++++++++++++++++++++
 demos/gtk-demo/gtkshaderstack.c   | 356 ++++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/gtkshaderstack.h   |  19 ++
 demos/gtk-demo/meson.build        |   2 +
 demos/gtk-demo/transition1.glsl   |  32 ++++
 demos/gtk-demo/transition2.glsl   |  33 ++++
 demos/gtk-demo/transition3.glsl   |  26 +++
 demos/gtk-demo/transition4.glsl   |  40 +++++
 9 files changed, 767 insertions(+)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 5953feaaef..d5e3c11590 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -138,6 +138,14 @@
     <file>gtkshaderbin.h</file>
     <file>gtkshaderbin.c</file>
   </gresource>
+  <gresource prefix="/gltransition">
+    <file>gtkshaderstack.c</file>
+    <file>gtkshaderstack.h</file>
+    <file>transition1.glsl</file>
+    <file>transition2.glsl</file>
+    <file>transition3.glsl</file>
+    <file>transition4.glsl</file>
+  </gresource>
   <gresource prefix="/iconscroll">
     <file>iconscroll.ui</file>
   </gresource>
@@ -253,6 +261,7 @@
     <file>gestures.c</file>
     <file>glarea.c</file>
     <file>glshader.c</file>
+    <file>gltransition.c</file>
     <file>headerbar.c</file>
     <file>hypertext.c</file>
     <file>iconscroll.c</file>
diff --git a/demos/gtk-demo/gltransition.c b/demos/gtk-demo/gltransition.c
new file mode 100644
index 0000000000..f29731b9a3
--- /dev/null
+++ b/demos/gtk-demo/gltransition.c
@@ -0,0 +1,250 @@
+/* OpenGL/Transitions
+ * #Keywords: OpenGL, shader
+ *
+ * Create transitions between pages using a custom fragment shader.
+ * The examples here are taken from gl-transitions.com.
+ *
+ * Click to start a transition.
+ */
+
+#include <math.h>
+#include <gtk/gtk.h>
+#include "gtkshaderstack.h"
+
+static GtkWidget *demo_window = NULL;
+
+static void
+close_window (GtkWidget *widget)
+{
+  /* Reset the state */
+  demo_window = NULL;
+}
+
+static GskGLShader *
+gsk_shader_new_from_resource (const char *resource_path)
+{
+  GBytes *shader_b;
+  GskGLShader *shader;
+
+  shader_b = g_resources_lookup_data (resource_path, 0, NULL);
+  shader = gsk_glshader_new ((const char *)g_bytes_get_data (shader_b, NULL));
+  gsk_glshader_set_n_required_sources (shader, 2);
+  gsk_glshader_add_uniform (shader, "progress", GSK_GLUNIFORM_TYPE_FLOAT);
+  g_bytes_unref (shader_b);
+
+  return shader;
+}
+
+static void
+text_changed (GtkTextBuffer *buffer,
+              GtkWidget     *button)
+{
+  gtk_widget_show (button);
+}
+
+static void
+apply_text (GtkWidget     *button,
+            GtkTextBuffer *buffer)
+{
+  GtkWidget *stack;
+  GskGLShader *shader;
+  GtkTextIter start, end;
+  char *text;
+
+  stack = gtk_widget_get_ancestor (button, GTK_TYPE_SHADER_STACK);
+
+  gtk_text_buffer_get_bounds (buffer, &start, &end);
+  text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
+
+  shader = gsk_glshader_new (text);
+  gsk_glshader_set_n_required_sources (shader, 2);
+  gsk_glshader_add_uniform (shader, "progress", GSK_GLUNIFORM_TYPE_FLOAT);
+
+  gtk_shader_stack_set_shader (GTK_SHADER_STACK (stack), shader);
+
+  g_object_unref (shader);
+  g_free (text);
+
+  gtk_widget_hide (button);
+}
+
+static void
+clicked_cb (GtkGestureClick *gesture,
+            guint            n_pressed,
+            double           x,
+            double           y,
+            gpointer         data)
+{
+  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static GtkWidget *
+make_shader_stack (const char *name,
+                   const char *resource_path,
+                   GtkWidget  *scale)
+{
+  GtkWidget *stack, *child, *widget;
+  GtkWidget *label, *button, *tv;
+  GskGLShader *shader;
+  GObjectClass *class;
+  GParamSpecFloat *pspec;
+  GtkAdjustment *adjustment;
+  GtkTextBuffer *buffer;
+  GBytes *bytes;
+  GtkEventController *controller;
+  GtkCssProvider *provider;
+
+  stack = gtk_shader_stack_new ();
+  shader = gsk_shader_new_from_resource (resource_path);
+  gtk_shader_stack_set_shader (GTK_SHADER_STACK (stack), shader);
+  g_object_unref (shader);
+
+  child = gtk_picture_new_for_resource ("/css_pixbufs/background.jpg");
+  gtk_picture_set_can_shrink (GTK_PICTURE (child), TRUE);
+  gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
+
+  child = gtk_picture_new_for_resource ("/transparent/portland-rose.jpg");
+  gtk_picture_set_can_shrink (GTK_PICTURE (child), TRUE);
+  gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
+
+  child = gtk_picture_new_for_resource ("/css_blendmodes/ducky.png");
+  gtk_picture_set_can_shrink (GTK_PICTURE (child), TRUE);
+  gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
+
+  child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+
+  widget = gtk_center_box_new ();
+  label = gtk_label_new (name);
+  gtk_widget_add_css_class (label, "title-4");
+  gtk_widget_set_size_request (label, -1, 26);
+  gtk_center_box_set_center_widget (GTK_CENTER_BOX (widget), label);
+
+  button = gtk_button_new_from_icon_name ("view-refresh-symbolic");
+  provider = gtk_css_provider_new ();
+  gtk_css_provider_load_from_data (provider, "button.small { padding: 0; }", -1);
+  gtk_style_context_add_provider (gtk_widget_get_style_context (button),
+                                  GTK_STYLE_PROVIDER (provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+  g_object_unref (provider);
+  gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
+  gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
+  gtk_widget_add_css_class (button, "small");
+  gtk_widget_hide (button);
+  gtk_center_box_set_end_widget (GTK_CENTER_BOX (widget), button);
+
+  gtk_box_append (GTK_BOX (child), widget);
+
+  class = g_type_class_ref (GTK_TYPE_SHADER_STACK);
+  pspec = G_PARAM_SPEC_FLOAT (g_object_class_find_property (class, "duration"));
+
+  adjustment = gtk_range_get_adjustment (GTK_RANGE (scale));
+  if (gtk_adjustment_get_lower (adjustment) == 0.0 &&
+      gtk_adjustment_get_upper (adjustment) == 0.0)
+    {
+      gtk_adjustment_configure (adjustment,
+                                pspec->default_value,
+                                pspec->minimum,
+                                pspec->maximum,
+                                0.1, 0.5, 0);
+    }
+
+  g_type_class_unref (class);
+
+  g_object_bind_property (adjustment, "value",
+                          stack, "duration",
+                          G_BINDING_DEFAULT);
+
+  widget = gtk_scrolled_window_new ();
+  gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (widget), TRUE);
+  gtk_widget_set_hexpand (widget, TRUE);
+  gtk_widget_set_vexpand (widget, TRUE);
+
+  controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
+  g_signal_connect (controller, "released", G_CALLBACK (clicked_cb), NULL);
+  gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
+  gtk_widget_add_controller (GTK_WIDGET (widget), controller);
+
+  tv = gtk_text_view_new ();
+  gtk_text_view_set_left_margin (GTK_TEXT_VIEW (tv), 4);
+  gtk_text_view_set_right_margin (GTK_TEXT_VIEW (tv), 4);
+  gtk_text_view_set_top_margin (GTK_TEXT_VIEW (tv), 4);
+  gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (tv), 4);
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
+  bytes = g_resources_lookup_data (resource_path, 0, NULL);
+  gtk_text_buffer_set_text (buffer,
+                            (const char *)g_bytes_get_data (bytes, NULL),
+                            g_bytes_get_size (bytes));
+  g_bytes_unref (bytes);
+  gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (widget), tv);
+
+  g_signal_connect (buffer, "changed", G_CALLBACK (text_changed), button);
+  g_signal_connect (button, "clicked", G_CALLBACK (apply_text), buffer);
+
+  gtk_box_append (GTK_BOX (child), widget);
+
+  gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
+
+  return stack;
+}
+
+static GtkWidget *
+create_gltransition_window (GtkWidget *do_widget)
+{
+  GtkWidget *window, *headerbar, *scale, *grid;
+
+  window = gtk_window_new ();
+  gtk_window_set_display (GTK_WINDOW (window),  gtk_widget_get_display (do_widget));
+  gtk_window_set_title (GTK_WINDOW (window), "Transitions");
+  headerbar = gtk_header_bar_new ();
+  scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, NULL);
+  gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+  gtk_widget_set_size_request (scale, 100, -1);
+  gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), scale);
+  gtk_window_set_titlebar (GTK_WINDOW (window), headerbar);
+  gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
+  g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
+
+  grid = gtk_grid_new ();
+  gtk_window_set_child (GTK_WINDOW (window), grid);
+
+  gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
+  gtk_widget_set_valign (grid, GTK_ALIGN_CENTER);
+  gtk_widget_set_margin_start (grid, 12);
+  gtk_widget_set_margin_end (grid, 12);
+  gtk_widget_set_margin_top (grid, 12);
+  gtk_widget_set_margin_bottom (grid, 12);
+  gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
+  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
+  gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE);
+  gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
+
+  gtk_grid_attach (GTK_GRID (grid),
+                   make_shader_stack ("Wind", "/gltransition/transition1.glsl", scale),
+                   0, 0, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid),
+                   make_shader_stack ("Radial", "/gltransition/transition2.glsl", scale),
+                   1, 0, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid),
+                   make_shader_stack ("Crosswarp", "/gltransition/transition3.glsl", scale),
+                   0, 1, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid),
+                   make_shader_stack ("Kaleidoscope", "/gltransition/transition4.glsl", scale),
+                   1, 1, 1, 1);
+
+  return window;
+}
+
+GtkWidget *
+do_gltransition (GtkWidget *do_widget)
+{
+  if (!demo_window)
+    demo_window = create_gltransition_window (do_widget);
+
+  if (!gtk_widget_get_visible (demo_window))
+    gtk_widget_show (demo_window);
+  else
+    gtk_window_destroy (GTK_WINDOW (demo_window));
+
+  return demo_window;
+}
diff --git a/demos/gtk-demo/gtkshaderstack.c b/demos/gtk-demo/gtkshaderstack.c
new file mode 100644
index 0000000000..0f9a7b0c20
--- /dev/null
+++ b/demos/gtk-demo/gtkshaderstack.c
@@ -0,0 +1,356 @@
+#include "gtkshaderstack.h"
+
+struct _GtkShaderStack
+{
+  GtkWidget parent_instance;
+
+  GskGLShader *shader;
+  GPtrArray *children;
+  int current;
+  int next;
+  gboolean backwards;
+
+  guint tick_id;
+  float time;
+  float duration;
+  gint64 start_time;
+};
+
+struct _GtkShaderStackClass
+{
+  GtkWidgetClass parent_class;
+};
+
+
+enum {
+  PROP_DURATION = 1,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
+
+G_DEFINE_TYPE (GtkShaderStack, gtk_shader_stack, GTK_TYPE_WIDGET)
+
+static void
+gtk_shader_stack_finalize (GObject *object)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (object);
+
+  g_object_unref (self->shader);
+
+  G_OBJECT_CLASS (gtk_shader_stack_parent_class)->finalize (object);
+}
+
+static void
+update_child_visible (GtkShaderStack *self)
+{
+  int i;
+
+  for (i = 0; i < self->children->len; i++)
+    {
+      GtkWidget *child = g_ptr_array_index (self->children, i);
+
+      gtk_widget_set_child_visible (child,
+                                    i == self->current || i == self->next);
+    }
+}
+
+static gboolean
+transition_cb (GtkWidget     *widget,
+               GdkFrameClock *clock,
+               gpointer       unused)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (widget);
+  gint64 frame_time;
+
+  frame_time = gdk_frame_clock_get_frame_time (clock);
+
+  if (self->start_time == 0)
+    self->start_time = frame_time;
+
+  self->time = (frame_time - self->start_time) / (float)G_USEC_PER_SEC;
+
+  gtk_widget_queue_draw (widget);
+
+  if (self->time >= self->duration)
+    {
+      self->current = self->next;
+      self->next = -1;
+
+      update_child_visible (self);
+
+      return G_SOURCE_REMOVE;
+    }
+  else
+    return G_SOURCE_CONTINUE;
+}
+
+static void
+start_transition (GtkShaderStack *self)
+{
+  self->start_time = 0;
+  self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self),
+                                                transition_cb,
+                                                NULL, NULL);
+}
+
+static void
+stop_transition (GtkShaderStack *self)
+{
+  if (self->tick_id != 0)
+    {
+      gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick_id);
+      self->tick_id = 0;
+    }
+
+  self->next = -1;
+
+  update_child_visible (self);
+}
+
+static void
+gtk_shader_stack_dispose (GObject *object)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (object);
+
+  stop_transition (self);
+
+  g_clear_pointer (&self->children, g_ptr_array_unref);
+
+  G_OBJECT_CLASS (gtk_shader_stack_parent_class)->dispose (object);
+}
+
+static void
+clicked_cb (GtkGestureClick *gesture,
+            guint            n_pressed,
+            double           x,
+            double           y,
+            gpointer         data)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (data);
+  guint button;
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+
+  stop_transition (self);
+
+  self->backwards = button == GDK_BUTTON_SECONDARY;
+  if (self->backwards)
+    self->next = (self->current + self->children->len - 1) % self->children->len;
+  else
+    self->next = (self->current + 1) % self->children->len;
+
+  update_child_visible (self);
+
+  start_transition (self);
+}
+
+static void
+gtk_shader_stack_init (GtkShaderStack *self)
+{
+  GtkEventController *controller;
+
+  self->children = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_widget_unparent);
+  self->current = -1;
+  self->next = -1;
+  self->backwards = FALSE;
+  self->duration = 1.0;
+
+  controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
+  g_signal_connect (controller, "released", G_CALLBACK (clicked_cb), self);
+  gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
+  gtk_widget_add_controller (GTK_WIDGET (self), controller);
+}
+
+static void
+gtk_shader_stack_measure (GtkWidget      *widget,
+                          GtkOrientation  orientation,
+                          int             for_size,
+                          int            *minimum,
+                          int            *natural,
+                          int            *minimum_baseline,
+                          int            *natural_baseline)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (widget);
+  int i;
+
+  *minimum = 0;
+  *natural = 0;
+
+  for (i = 0; i < self->children->len; i++)
+    {
+      GtkWidget *child = g_ptr_array_index (self->children, i);
+      int child_min, child_nat;
+
+      if (gtk_widget_get_visible (child))
+        {
+          gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL);
+
+          *minimum = MAX (*minimum, child_min);
+          *natural = MAX (*natural, child_nat);
+        }
+    }
+}
+
+static void
+gtk_shader_stack_size_allocate (GtkWidget *widget,
+                                int        width,
+                                int        height,
+                                int        baseline)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (widget);
+  GtkAllocation child_allocation;
+  GtkWidget *child;
+  int i;
+
+  child_allocation.x = 0;
+  child_allocation.y = 0;
+  child_allocation.width = width;
+  child_allocation.height = height;
+
+  for (i = 0; i < self->children->len; i++)
+    {
+      child = g_ptr_array_index (self->children, i);
+      if (gtk_widget_get_visible (child))
+        gtk_widget_size_allocate (child, &child_allocation, -1);
+    }
+}
+
+static void
+gtk_shader_stack_snapshot (GtkWidget   *widget,
+                           GtkSnapshot *snapshot)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (widget);
+  int width, height;
+  GtkWidget *current, *next;
+
+  width = gtk_widget_get_width (widget);
+  height = gtk_widget_get_height (widget);
+
+  current = g_ptr_array_index (self->children, self->current);
+
+  if (self->next == -1)
+    {
+      gtk_widget_snapshot_child (widget, current, snapshot);
+    }
+  else
+    {
+      float progress;
+
+      next = g_ptr_array_index (self->children, self->next);
+
+      progress = self->time / self->duration;
+
+      if (self->backwards)
+        {
+          GtkWidget *tmp = next;
+          next = current;
+          current = tmp;
+          progress = 1. - progress;
+        }
+
+      gtk_snapshot_push_glshader (snapshot,
+                                  self->shader,
+                                  &GRAPHENE_RECT_INIT(0, 0, width, height),
+                                  2,
+                                  "progress", &progress,
+                                  NULL);
+      gtk_widget_snapshot_child (widget, next, snapshot);
+      gtk_snapshot_pop (snapshot); /* Fallback */
+      gtk_widget_snapshot_child (widget, current, snapshot);
+      gtk_snapshot_pop (snapshot); /* current child */
+      gtk_widget_snapshot_child (widget, next, snapshot);
+      gtk_snapshot_pop (snapshot); /* next child */
+    }
+}
+
+static void
+gtk_shader_stack_get_property (GObject      *object,
+                               guint         prop_id,
+                               GValue       *value,
+                               GParamSpec   *pspec)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (object);
+
+  switch (prop_id)
+    {
+    case PROP_DURATION:
+      g_value_set_float (value, self->duration);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_shader_stack_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+  GtkShaderStack *self = GTK_SHADER_STACK (object);
+
+  switch (prop_id)
+    {
+    case PROP_DURATION:
+      self->duration = g_value_get_float (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_shader_stack_class_init (GtkShaderStackClass *class)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = gtk_shader_stack_finalize;
+  object_class->dispose = gtk_shader_stack_dispose;
+  object_class->get_property = gtk_shader_stack_get_property;
+  object_class->set_property = gtk_shader_stack_set_property;
+
+  widget_class->snapshot = gtk_shader_stack_snapshot;
+  widget_class->measure = gtk_shader_stack_measure;
+  widget_class->size_allocate = gtk_shader_stack_size_allocate;
+
+  properties[PROP_DURATION] =
+      g_param_spec_float ("duration", "Duration", "Duration",
+                          0.1, 3.0, 1.0,
+                          G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+}
+
+GtkWidget *
+gtk_shader_stack_new (void)
+{
+  return g_object_new (GTK_TYPE_SHADER_STACK, NULL);
+}
+
+void
+gtk_shader_stack_set_shader (GtkShaderStack *self,
+                             GskGLShader    *shader)
+{
+  g_set_object (&self->shader, shader);
+}
+
+void
+gtk_shader_stack_add_child (GtkShaderStack *self,
+                            GtkWidget      *child)
+{
+  g_ptr_array_add (self->children, child);
+  gtk_widget_set_parent (child, GTK_WIDGET (self));
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  if (self->current == -1)
+    self->current = 0;
+  else
+    gtk_widget_set_child_visible (child, FALSE);
+}
diff --git a/demos/gtk-demo/gtkshaderstack.h b/demos/gtk-demo/gtkshaderstack.h
new file mode 100644
index 0000000000..19ee849b1b
--- /dev/null
+++ b/demos/gtk-demo/gtkshaderstack.h
@@ -0,0 +1,19 @@
+#ifndef __GTK_SHADER_STACK_H__
+#define __GTK_SHADER_STACK_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SHADER_STACK     (gtk_shader_stack_get_type ())
+G_DECLARE_FINAL_TYPE (GtkShaderStack, gtk_shader_stack, GTK, SHADER_STACK, GtkWidget)
+
+GtkWidget * gtk_shader_stack_new          (void);
+void        gtk_shader_stack_set_shader   (GtkShaderStack *self,
+                                           GskGLShader    *shader);
+void        gtk_shader_stack_add_child    (GtkShaderStack *self,
+                                           GtkWidget      *child);
+
+G_END_DECLS
+
+#endif /* __GTK_SHADER_STACK_H__ */
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index cbc52bcca6..b80ae3bbb3 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -33,6 +33,7 @@ demos = files([
   'gestures.c',
   'glarea.c',
   'glshader.c',
+  'gltransition.c',
   'headerbar.c',
   'hypertext.c',
   'iconscroll.c',
@@ -105,6 +106,7 @@ extra_demo_sources = files(['main.c',
                             'gtkgears.c',
                             'gtkshaderbin.c',
                             'gtkshadertoy.c',
+                            'gtkshaderstack.c',
                             'puzzlepiece.c',
                             'bluroverlay.c',
                             'demoimage.c',
diff --git a/demos/gtk-demo/transition1.glsl b/demos/gtk-demo/transition1.glsl
new file mode 100644
index 0000000000..1cd6c7b997
--- /dev/null
+++ b/demos/gtk-demo/transition1.glsl
@@ -0,0 +1,32 @@
+uniform float progress;
+
+vec4 getFromColor(vec2 uv) {
+  return texture(u_source, uv);
+}
+
+vec4 getToColor(vec2 uv) {
+  return texture(u_source2, uv);
+}
+
+
+// Source: https://gl-transitions.com/editor/wind
+// Author: gre
+// License: MIT
+
+uniform float size = 0.2;
+
+float rand(vec2 co) {
+  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
+}
+
+vec4 transition(vec2 p) {
+  float r = rand(vec2(0, p.y));
+  float m = smoothstep(0.0, -size, p.x*(1.0-size) + size*r - (progress * (1.0 + size)));
+  return mix(getFromColor(p), getToColor(p), m);
+}
+
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
+{
+  fragColor = transition(uv);
+}
diff --git a/demos/gtk-demo/transition2.glsl b/demos/gtk-demo/transition2.glsl
new file mode 100644
index 0000000000..f79c9b871c
--- /dev/null
+++ b/demos/gtk-demo/transition2.glsl
@@ -0,0 +1,33 @@
+uniform float progress;
+
+vec4 getFromColor (vec2 uv) {
+  return texture(u_source, uv);
+}
+
+vec4 getToColor (vec2 uv) {
+  return texture(u_source2, uv);
+}
+
+
+// Source: https://gl-transitions.com/editor/Radial
+// License: MIT
+// Author: Xaychru
+
+uniform float smoothness = 1.0;
+
+const float PI = 3.141592653589;
+
+vec4 transition(vec2 p) {
+  vec2 rp = p*2.-1.;
+  return mix(
+    getToColor(p),
+    getFromColor(p),
+    smoothstep(0., smoothness, atan(rp.y,rp.x) - (progress-.5) * PI * 2.5)
+  );
+}
+
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
+{
+  fragColor = transition(uv);
+}
diff --git a/demos/gtk-demo/transition3.glsl b/demos/gtk-demo/transition3.glsl
new file mode 100644
index 0000000000..f949b3841b
--- /dev/null
+++ b/demos/gtk-demo/transition3.glsl
@@ -0,0 +1,26 @@
+uniform float progress;
+
+vec4 getFromColor (vec2 uv) {
+  return texture(u_source, uv);
+}
+
+vec4 getToColor (vec2 uv) {
+  return texture(u_source2, uv);
+}
+
+
+// Source: https://gl-transitions.com/editor/crosswarp
+// Author: Eke Péter <peterekepeter gmail com>
+// License: MIT
+
+vec4 transition(vec2 p) {
+  float x = progress;
+  x=smoothstep(.0,1.0,(x*2.0+p.x-1.0));
+  return mix(getFromColor((p-.5)*(1.-x)+.5), getToColor((p-.5)*x+.5), x);
+}
+
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
+{
+  fragColor = transition(uv);
+}
diff --git a/demos/gtk-demo/transition4.glsl b/demos/gtk-demo/transition4.glsl
new file mode 100644
index 0000000000..4e36b3c8ac
--- /dev/null
+++ b/demos/gtk-demo/transition4.glsl
@@ -0,0 +1,40 @@
+uniform float progress;
+
+vec4 getFromColor (vec2 uv) {
+  return texture(u_source, uv);
+}
+
+vec4 getToColor (vec2 uv) {
+  return texture(u_source2, uv);
+}
+
+
+// Source: https://gl-transitions.com/editor/kaleidoscope
+// Author: nwoeanhinnogaehr
+// License: MIT
+
+uniform float speed = 1.0;
+uniform float angle = 1.0;
+uniform float power = 1.5;
+
+vec4 transition(vec2 uv) {
+  vec2 p = uv.xy / vec2(1.0).xy;
+  vec2 q = p;
+  float t = pow(progress, power)*speed;
+  p = p -0.5;
+  for (int i = 0; i < 7; i++) {
+    p = vec2(sin(t)*p.x + cos(t)*p.y, sin(t)*p.y - cos(t)*p.x);
+    t += angle;
+    p = abs(mod(p, 2.0) - 1.0);
+  }
+  abs(mod(p, 1.0));
+  return mix(
+    mix(getFromColor(q), getToColor(q), progress),
+    mix(getFromColor(p), getToColor(p), progress), 1.0 - 2.0*abs(progress - 0.5));
+}
+
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
+{
+  fragColor = transition(uv);
+}


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