[gtk/matthiasc/gltransition-demo: 8/10] gtk-demo: Add GskGLShaderNode demo
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/gltransition-demo: 8/10] gtk-demo: Add GskGLShaderNode demo
- Date: Tue, 22 Sep 2020 15:20:06 +0000 (UTC)
commit 91f4c4a967378529022c92b3f3b7a9c58a7d464f
Author: Alexander Larsson <alexl redhat com>
Date: Mon Sep 21 21:05:04 2020 +0200
gtk-demo: Add GskGLShaderNode demo
demos/gtk-demo/demo.gresource.xml | 6 ++
demos/gtk-demo/fire.glsl | 72 +++++++++++++
demos/gtk-demo/glshader.c | 85 +++++++++++++++
demos/gtk-demo/gtkshaderbin.c | 220 ++++++++++++++++++++++++++++++++++++++
demos/gtk-demo/gtkshaderbin.h | 22 ++++
demos/gtk-demo/meson.build | 2 +
6 files changed, 407 insertions(+)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 39d6ad2db8..5953feaaef 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -133,6 +133,11 @@
<file>cogs.glsl</file>
<file>glowingstars.glsl</file>
</gresource>
+ <gresource prefix="/glshader">
+ <file>fire.glsl</file>
+ <file>gtkshaderbin.h</file>
+ <file>gtkshaderbin.c</file>
+ </gresource>
<gresource prefix="/iconscroll">
<file>iconscroll.ui</file>
</gresource>
@@ -247,6 +252,7 @@
<file>gears.c</file>
<file>gestures.c</file>
<file>glarea.c</file>
+ <file>glshader.c</file>
<file>headerbar.c</file>
<file>hypertext.c</file>
<file>iconscroll.c</file>
diff --git a/demos/gtk-demo/fire.glsl b/demos/gtk-demo/fire.glsl
new file mode 100644
index 0000000000..58147cbbb2
--- /dev/null
+++ b/demos/gtk-demo/fire.glsl
@@ -0,0 +1,72 @@
+uniform float u_time;
+
+/* 2D -> [0..1] random number generator */
+float random(vec2 st) {
+ return fract(sin(dot(st.xy,
+ vec2(12.9898,78.233))) *
+ 43758.5453123);
+}
+
+/* Generate a smoothed 2d noise based on random() */
+float noise(vec2 v) {
+ /* Round point v to integer grid grid */
+ vec2 grid_point = floor(v);
+ /* Randomize in grid corners */
+ float corner1 = random(grid_point);
+ float corner2 = random(grid_point + vec2(1, 0));
+ float corner3 = random(grid_point + vec2(0, 1));
+ float corner4 = random(grid_point + vec2(1, 1));
+ /* Interpolate smoothly between grid points */
+ vec2 fraction = smoothstep(vec2(0.0), vec2(1.0), fract(v));
+ return mix(mix(corner1, corner2, fraction.x),
+ mix(corner3, corner4, fraction.x),
+ fraction.y);
+}
+
+/* fractal brownian motion noice, see https://www.iquilezles.org/www/articles/fbm/fbm.htm */
+float fbm(in vec2 x)
+{
+ const float octaveScale = 1.9;
+ const float G = 0.5;
+ float f = 1.0;
+ float a = 1.0;
+ float t = 0.0;
+ int numOctaves = 5;
+ for (int i = 0; i < numOctaves; i++) {
+ t += a*noise(f*x);
+ f *= octaveScale;
+ a *= G;
+ }
+
+ return t;
+}
+
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
+{
+ vec2 xy = fragCoord / resolution;
+
+ float zoom = 3.0 - sin(u_time*0.5)*0.3;
+
+ // Normalize coord to height of widget
+ vec2 p = (vec2 (-resolution.x/2 + fragCoord.x, resolution.y - fragCoord.y) / resolution.yy)* zoom;
+
+ // Use recursive incantations of fbm
+ float q1 = fbm(p - vec2(0.8, 0.3) * u_time);
+ float q2 = fbm(p - vec2(0.5, 1.3) * u_time);
+ float r = fbm(2.0*p + vec2(q1,q2) - vec2(0.0, 1.0)*u_time*10.0 *0.4);
+
+ // Compute intensity, mostly on the bottom
+ float w = 2 * r * p.y;
+
+ // Smooth out left/right side and fade in at start
+ w /= smoothstep(0.0,0.1, xy.x)* smoothstep(0.0,0.1, 1.0-xy.x) * smoothstep(0.0,0.4, u_time);
+
+ // Compute colors
+ vec3 c = vec3(1.0,.2,.05);
+ vec3 color = 1.0 / (w*w/c + 1.0);
+
+ // Mix in widget
+ vec4 widget = texture(u_source,uv);
+ fragColor = mix(vec4(color,1), widget, 1.0-color.x);
+}
diff --git a/demos/gtk-demo/glshader.c b/demos/gtk-demo/glshader.c
new file mode 100644
index 0000000000..8bf8fccd65
--- /dev/null
+++ b/demos/gtk-demo/glshader.c
@@ -0,0 +1,85 @@
+/* OpenGL/GLShader
+ * #Keywords: OpenGL, shader
+ *
+ * Demonstrates using GskGLShaderNodes to integrate GLSL fragment shaders
+ * with the Gtk widget rendering.
+ */
+#include <math.h>
+#include <gtk/gtk.h>
+#include "gtkshaderbin.h"
+
+static GtkWidget *demo_window = NULL;
+
+static void
+close_window (GtkWidget *widget)
+{
+ /* Reset the state */
+ demo_window = NULL;
+}
+
+static GtkWidget *
+fire_bin_new (void)
+{
+ GtkWidget *bin = gtk_shader_bin_new ();
+ GBytes *shader_b;
+ GskGLShader *shader;
+
+ shader_b = g_resources_lookup_data ("/glshader/fire.glsl", 0, NULL);
+ shader = gsk_glshader_new ((const char *)g_bytes_get_data (shader_b, NULL));
+ gsk_glshader_add_uniform (shader, "u_time", GSK_GLUNIFORM_TYPE_FLOAT);
+ gtk_shader_bin_add_shader (GTK_SHADER_BIN (bin), shader, GTK_STATE_FLAG_PRELIGHT, GTK_STATE_FLAG_PRELIGHT);
+ g_bytes_unref (shader_b);
+ g_object_unref (shader);
+
+ return bin;
+}
+
+
+static GtkWidget *
+create_glshader_window (GtkWidget *do_widget)
+{
+ GtkWidget *window, *box, *button, *bin;
+
+ window = gtk_window_new ();
+ gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
+ gtk_window_set_title (GTK_WINDOW (window), "glshader");
+ g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
+ gtk_widget_set_margin_start (box, 12);
+ gtk_widget_set_margin_end (box, 12);
+ gtk_widget_set_margin_top (box, 12);
+ gtk_widget_set_margin_bottom (box, 12);
+ gtk_box_set_spacing (GTK_BOX (box), 6);
+ gtk_window_set_child (GTK_WINDOW (window), box);
+
+ bin = fire_bin_new ();
+ gtk_box_append (GTK_BOX (box), bin);
+
+ button = gtk_button_new_with_label ("Click me");
+ gtk_widget_set_receives_default (button, TRUE);
+ gtk_shader_bin_set_child (GTK_SHADER_BIN (bin), button);
+
+ bin = fire_bin_new ();
+ gtk_box_append (GTK_BOX (box), bin);
+
+ button = gtk_button_new_with_label ("Or me!");
+ gtk_widget_set_receives_default (button, TRUE);
+ gtk_shader_bin_set_child (GTK_SHADER_BIN (bin), button);
+
+ return window;
+}
+
+GtkWidget *
+do_glshader (GtkWidget *do_widget)
+{
+ if (!demo_window)
+ demo_window = create_glshader_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/gtkshaderbin.c b/demos/gtk-demo/gtkshaderbin.c
new file mode 100644
index 0000000000..abdf226942
--- /dev/null
+++ b/demos/gtk-demo/gtkshaderbin.c
@@ -0,0 +1,220 @@
+#include "gtkshaderbin.h"
+
+typedef struct {
+ GskGLShader *shader;
+ GtkStateFlags state;
+ GtkStateFlags state_mask;
+} ShaderInfo;
+
+struct _GtkShaderBin
+{
+ GtkWidget parent_instance;
+ GtkWidget *child;
+ GskGLShader *active_shader;
+ GPtrArray *shaders;
+ guint tick_id;
+ float time;
+ gint64 first_frame_time;
+};
+
+struct _GtkShaderBinClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkShaderBin, gtk_shader_bin, GTK_TYPE_WIDGET)
+
+static void
+shader_info_free (ShaderInfo *info)
+{
+ g_object_unref (info->shader);
+ g_free (info);
+}
+
+static void
+gtk_shader_bin_finalize (GObject *object)
+{
+ GtkShaderBin *self = GTK_SHADER_BIN (object);
+
+ g_ptr_array_free (self->shaders, TRUE);
+
+ G_OBJECT_CLASS (gtk_shader_bin_parent_class)->finalize (object);
+}
+
+static void
+gtk_shader_bin_dispose (GObject *object)
+{
+ GtkShaderBin *self = GTK_SHADER_BIN (object);
+
+ g_clear_pointer (&self->child, gtk_widget_unparent);
+
+ G_OBJECT_CLASS (gtk_shader_bin_parent_class)->dispose (object);
+}
+
+static gboolean
+gtk_shader_bin_tick (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ gpointer unused)
+{
+ GtkShaderBin *self = GTK_SHADER_BIN (widget);
+ gint64 frame_time;
+
+ frame_time = gdk_frame_clock_get_frame_time (frame_clock);
+ if (self->first_frame_time == 0)
+ self->first_frame_time = frame_time;
+ self->time = (frame_time - self->first_frame_time) / (float)G_USEC_PER_SEC;
+
+ gtk_widget_queue_draw (widget);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+gtk_shader_bin_init (GtkShaderBin *self)
+{
+ self->shaders = g_ptr_array_new_with_free_func ((GDestroyNotify)shader_info_free);
+}
+
+void
+gtk_shader_bin_update_active_shader (GtkShaderBin *self)
+{
+ GtkStateFlags new_state = gtk_widget_get_state_flags (GTK_WIDGET (self));
+ GskGLShader *new_shader = NULL;
+
+ for (int i = 0; i < self->shaders->len; i++)
+ {
+ ShaderInfo *info = g_ptr_array_index (self->shaders, i);
+
+ if ((info->state_mask & new_state) == info->state)
+ {
+ new_shader = info->shader;
+ break;
+ }
+ }
+
+ if (self->active_shader == new_shader)
+ return;
+
+ self->active_shader = new_shader;
+ self->first_frame_time = 0;
+
+ if (self->active_shader)
+ {
+ if (self->tick_id == 0)
+ self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self),
+ gtk_shader_bin_tick,
+ NULL, NULL);
+ }
+ else
+ {
+ if (self->tick_id != 0)
+ {
+ gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick_id);
+ self->tick_id = 0;
+ }
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+gtk_shader_bin_state_flags_changed (GtkWidget *widget,
+ GtkStateFlags previous_state_flags)
+{
+ GtkShaderBin *self = GTK_SHADER_BIN (widget);
+
+ gtk_shader_bin_update_active_shader (self);
+}
+
+void
+gtk_shader_bin_add_shader (GtkShaderBin *self,
+ GskGLShader *shader,
+ GtkStateFlags state,
+ GtkStateFlags state_mask)
+{
+ ShaderInfo *info = g_new0 (ShaderInfo, 1);
+ info->shader = g_object_ref (shader);
+ info->state = state;
+ info->state_mask = state_mask;
+
+ g_ptr_array_add (self->shaders, info);
+
+ gtk_shader_bin_update_active_shader (self);
+}
+
+void
+gtk_shader_bin_set_child (GtkShaderBin *self,
+ GtkWidget *child)
+{
+
+ if (self->child == child)
+ return;
+
+ g_clear_pointer (&self->child, gtk_widget_unparent);
+
+ if (child)
+ {
+ self->child = child;
+ gtk_widget_set_parent (child, GTK_WIDGET (self));
+ }
+}
+
+GtkWidget *
+gtk_shader_bin_get_child (GtkShaderBin *self)
+{
+ return self->child;
+}
+
+static void
+gtk_shader_bin_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ GtkShaderBin *self = GTK_SHADER_BIN (widget);
+ int width, height;
+
+ width = gtk_widget_get_width (widget);
+ height = gtk_widget_get_height (widget);
+
+ if (self->active_shader)
+ {
+ gtk_snapshot_push_glshader (snapshot, self->active_shader,
+ &GRAPHENE_RECT_INIT(0, 0, width, height),
+ 1,
+ "u_time", &self->time,
+ NULL
+ );
+ gtk_widget_snapshot_child (widget, self->child, snapshot);
+ gtk_snapshot_pop (snapshot); /* Fallback */
+ gtk_widget_snapshot_child (widget, self->child, snapshot);
+ gtk_snapshot_pop (snapshot); /* Shader node child 1 */
+ }
+ else
+ {
+ gtk_widget_snapshot_child (widget, self->child, snapshot);
+ }
+}
+
+static void
+gtk_shader_bin_class_init (GtkShaderBinClass *class)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = gtk_shader_bin_finalize;
+ object_class->dispose = gtk_shader_bin_dispose;
+
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+
+ widget_class->snapshot = gtk_shader_bin_snapshot;
+ widget_class->state_flags_changed = gtk_shader_bin_state_flags_changed;
+}
+
+GtkWidget *
+gtk_shader_bin_new (void)
+{
+ GtkShaderBin *self;
+
+ self = g_object_new (GTK_TYPE_SHADER_BIN, NULL);
+
+ return GTK_WIDGET (self);
+}
diff --git a/demos/gtk-demo/gtkshaderbin.h b/demos/gtk-demo/gtkshaderbin.h
new file mode 100644
index 0000000000..eabac8f0d6
--- /dev/null
+++ b/demos/gtk-demo/gtkshaderbin.h
@@ -0,0 +1,22 @@
+#ifndef __GTK_SHADER_BIN_H__
+#define __GTK_SHADER_BIN_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SHADER_BIN (gtk_shader_bin_get_type ())
+G_DECLARE_FINAL_TYPE (GtkShaderBin, gtk_shader_bin, GTK, SHADER_BIN, GtkWidget)
+
+GtkWidget *gtk_shader_bin_new (void);
+void gtk_shader_bin_add_shader (GtkShaderBin *self,
+ GskGLShader *shader,
+ GtkStateFlags state,
+ GtkStateFlags state_mask);
+void gtk_shader_bin_set_child (GtkShaderBin *self,
+ GtkWidget *child);
+GtkWidget *gtk_shader_bin_get_child (GtkShaderBin *self);
+
+G_END_DECLS
+
+#endif /* __GTK_SHADER_BIN_H__ */
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index a32fee88e5..cbc52bcca6 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -32,6 +32,7 @@ demos = files([
'gears.c',
'gestures.c',
'glarea.c',
+ 'glshader.c',
'headerbar.c',
'hypertext.c',
'iconscroll.c',
@@ -102,6 +103,7 @@ extra_demo_sources = files(['main.c',
'gtkfishbowl.c',
'fontplane.c',
'gtkgears.c',
+ 'gtkshaderbin.c',
'gtkshadertoy.c',
'puzzlepiece.c',
'bluroverlay.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]