Compare commits
29 Commits
async-colo
...
glshader-p
Author | SHA1 | Date | |
---|---|---|---|
|
f19001d4c3 | ||
|
6ecf612677 | ||
|
e0b3746655 | ||
|
1bc81fac2a | ||
|
bdcc29ebef | ||
|
810e9c238e | ||
|
e4dfa5597a | ||
|
32aa470f68 | ||
|
a234ab1e55 | ||
|
e93a51b1cc | ||
|
66cd15d858 | ||
|
a0bc9d65da | ||
|
a580c711e5 | ||
|
e91d5b82ce | ||
|
0516c59ff5 | ||
|
a3ea3f94dc | ||
|
5e9fe2f6e8 | ||
|
6613c523c2 | ||
|
efa0fa0bf4 | ||
|
1b6f7917ed | ||
|
8cc18d2c82 | ||
|
d97267b897 | ||
|
21e0ad0561 | ||
|
94cccc5e71 | ||
|
111dfdf3f5 | ||
|
0693deb02f | ||
|
ffd39c257a | ||
|
ec0ad5738c | ||
|
c958fd8e86 |
229
demos/gtk-demo/cogs2.glsl
Normal file
229
demos/gtk-demo/cogs2.glsl
Normal file
@@ -0,0 +1,229 @@
|
||||
uniform float iTime;
|
||||
|
||||
in vec2 fragCoord;
|
||||
out vec4 vFragColor;
|
||||
|
||||
// Originally from: https://www.shadertoy.com/view/3ljyDD
|
||||
// License CC0: Hexagonal tiling + cog wheels
|
||||
// Nothing fancy, just hexagonal tiling + cog wheels
|
||||
|
||||
#define PI 3.141592654
|
||||
#define TAU (2.0*PI)
|
||||
#define MROT(a) mat2(cos(a), sin(a), -sin(a), cos(a))
|
||||
|
||||
float hash(in vec2 co) {
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
|
||||
}
|
||||
|
||||
float pcos(float a) {
|
||||
return 0.5 + 0.5*cos(a);
|
||||
}
|
||||
|
||||
void rot(inout vec2 p, float a) {
|
||||
float c = cos(a);
|
||||
float s = sin(a);
|
||||
p = vec2(c*p.x + s*p.y, -s*p.x + c*p.y);
|
||||
}
|
||||
|
||||
float modPolar(inout vec2 p, float repetitions) {
|
||||
float angle = 2.0*PI/repetitions;
|
||||
float a = atan(p.y, p.x) + angle/2.;
|
||||
float r = length(p);
|
||||
float c = floor(a/angle);
|
||||
a = mod(a,angle) - angle/2.;
|
||||
p = vec2(cos(a), sin(a))*r;
|
||||
// For an odd number of repetitions, fix cell index of the cell in -x direction
|
||||
// (cell index would be e.g. -5 and 5 in the two halves of the cell):
|
||||
if (abs(c) >= (repetitions/2.0)) c = abs(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
float pmin(float a, float b, float k) {
|
||||
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
|
||||
return mix( b, a, h ) - k*h*(1.0-h);
|
||||
}
|
||||
|
||||
const vec2 sz = vec2(1.0, sqrt(3.0));
|
||||
const vec2 hsz = 0.5*sz;
|
||||
const float smallCount = 16.0;
|
||||
|
||||
vec2 hextile(inout vec2 p) {
|
||||
// See Art of Code: Hexagonal Tiling Explained!
|
||||
// https://www.youtube.com/watch?v=VmrIDyYiJBA
|
||||
|
||||
vec2 p1 = mod(p, sz)-hsz;
|
||||
vec2 p2 = mod(p - hsz*1.0, sz)-hsz;
|
||||
vec2 p3 = mix(p2, p1, vec2(length(p1) < length(p2)));
|
||||
vec2 n = p3 - p;
|
||||
p = p3;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
float circle(vec2 p, float r) {
|
||||
return length(p) - r;
|
||||
}
|
||||
|
||||
float box(vec2 p, vec2 b) {
|
||||
vec2 d = abs(p)-b;
|
||||
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
|
||||
}
|
||||
|
||||
float unevenCapsule(vec2 p, float r1, float r2, float h) {
|
||||
p.x = abs(p.x);
|
||||
float b = (r1-r2)/h;
|
||||
float a = sqrt(1.0-b*b);
|
||||
float k = dot(p,vec2(-b,a));
|
||||
if( k < 0.0 ) return length(p) - r1;
|
||||
if( k > a*h ) return length(p-vec2(0.0,h)) - r2;
|
||||
return dot(p, vec2(a,b) ) - r1;
|
||||
}
|
||||
|
||||
float cogwheel(vec2 p, float innerRadius, float outerRadius, float cogs, float holes) {
|
||||
float cogWidth = 0.25*innerRadius*TAU/cogs;
|
||||
|
||||
float d0 = circle(p, innerRadius);
|
||||
|
||||
vec2 icp = p;
|
||||
modPolar(icp, holes);
|
||||
icp -= vec2(innerRadius*0.55, 0.0);
|
||||
float d1 = circle(icp, innerRadius*0.25);
|
||||
|
||||
vec2 cp = p;
|
||||
modPolar(cp, cogs);
|
||||
cp -= vec2(innerRadius, 0.0);
|
||||
float d2 = unevenCapsule(cp.yx, cogWidth, cogWidth*0.75, (outerRadius-innerRadius));
|
||||
|
||||
float d3 = circle(p, innerRadius*0.20);
|
||||
|
||||
float d = 1E6;
|
||||
d = min(d, d0);
|
||||
d = pmin(d, d2, 0.5*cogWidth);
|
||||
d = min(d, d2);
|
||||
d = max(d, -d1);
|
||||
d = max(d, -d3);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
float ccell1(vec2 p, float r) {
|
||||
float d = 1E6;
|
||||
const float bigCount = 60.0;
|
||||
|
||||
vec2 cp0 = p;
|
||||
rot(cp0, -iTime*TAU/bigCount);
|
||||
float d0 = cogwheel(cp0, 0.36, 0.38, bigCount, 5.0);
|
||||
|
||||
vec2 cp1 = p;
|
||||
float nm = modPolar(cp1, 6.0);
|
||||
|
||||
cp1 -= vec2(0.5, 0.0);
|
||||
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
|
||||
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
|
||||
|
||||
d = min(d, d0);
|
||||
d = min(d, d1);
|
||||
return d;
|
||||
}
|
||||
|
||||
float ccell2(vec2 p, float r) {
|
||||
float d = 1E6;
|
||||
vec2 cp0 = p;
|
||||
float nm = modPolar(cp0, 6.0);
|
||||
vec2 cp1 = cp0;
|
||||
const float off = 0.275;
|
||||
const float count = smallCount + 2.0;
|
||||
cp0 -= vec2(off, 0.0);
|
||||
rot(cp0, 0.+TAU*nm/2.0 - iTime*TAU/count);
|
||||
float d0 = cogwheel(cp0, 0.09, 0.105, count, 5.0);
|
||||
|
||||
|
||||
cp1 -= vec2(0.5, 0.0);
|
||||
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
|
||||
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
|
||||
|
||||
float l = length(p);
|
||||
float d2 = l - (off+0.055);
|
||||
float d3 = d2 + 0.020;;
|
||||
|
||||
vec2 tp0 = p;
|
||||
modPolar(tp0, 60.0);
|
||||
tp0.x -= off;
|
||||
float d4 = box(tp0, vec2(0.0125, 0.005));
|
||||
|
||||
float ctime = -(iTime*0.05 + r)*TAU;
|
||||
|
||||
vec2 tp1 = p;
|
||||
rot(tp1, ctime*12.0);
|
||||
tp1.x -= 0.13;
|
||||
float d5 = box(tp1, vec2(0.125, 0.005));
|
||||
|
||||
vec2 tp2 = p;
|
||||
rot(tp2, ctime);
|
||||
tp2.x -= 0.13*0.5;
|
||||
float d6 = box(tp2, vec2(0.125*0.5, 0.0075));
|
||||
|
||||
float d7 = l - 0.025;
|
||||
float d8 = l - 0.0125;
|
||||
|
||||
d = min(d, d0);
|
||||
d = min(d, d1);
|
||||
d = min(d, d2);
|
||||
d = max(d, -d3);
|
||||
d = min(d, d4);
|
||||
d = min(d, d5);
|
||||
d = min(d, d6);
|
||||
d = min(d, d7);
|
||||
d = max(d, -d8);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
float df(vec2 p, float scale, inout vec2 nn) {
|
||||
p /= scale;
|
||||
nn = hextile(p);
|
||||
nn = round(nn);
|
||||
float r = hash(nn);
|
||||
|
||||
float d;;
|
||||
|
||||
if (r < 0.5) {
|
||||
d = ccell1(p, r);
|
||||
} else {
|
||||
d = ccell2(p, r);
|
||||
}
|
||||
|
||||
return d*scale;
|
||||
}
|
||||
|
||||
vec3 postProcess(vec3 col, vec2 q) {
|
||||
//col = saturate(col);
|
||||
col=pow(clamp(col,0.0,1.0),vec3(0.75));
|
||||
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
|
||||
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
|
||||
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
|
||||
return col;
|
||||
}
|
||||
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) {
|
||||
vec2 q = fragCoord/resolution.xy;
|
||||
vec2 p = -1.0 + 2.0*q;
|
||||
p.x *= resolution.x/resolution.y;
|
||||
float tm = iTime*0.1;
|
||||
p += vec2(cos(tm), sin(tm*sqrt(0.5)));
|
||||
float z = mix(0.5, 1.0, pcos(tm*sqrt(0.3)));
|
||||
float aa = 4.0 / resolution.y;
|
||||
|
||||
vec2 nn = vec2(0.0);
|
||||
float d = df(p, z, nn);
|
||||
|
||||
vec3 col = vec3(160.0)/vec3(255.0);
|
||||
vec3 baseCol = vec3(0.3);
|
||||
vec4 logoCol = vec4(baseCol, 1.0)*smoothstep(-aa, 0.0, -d);
|
||||
col = mix(col, logoCol.xyz, pow(logoCol.w, 8.0));
|
||||
col += 0.4*pow(abs(sin(20.0*d)), 0.6);
|
||||
|
||||
col = postProcess(col, q);
|
||||
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
@@ -133,6 +133,18 @@
|
||||
<file>cogs.glsl</file>
|
||||
<file>glowingstars.glsl</file>
|
||||
</gresource>
|
||||
<gresource prefix="/gltransition">
|
||||
<file>gtkshaderstack.c</file>
|
||||
<file>gtkshaderstack.h</file>
|
||||
<file>gtkshaderbin.h</file>
|
||||
<file>gtkshaderbin.c</file>
|
||||
<file>fire.glsl</file>
|
||||
<file>transition1.glsl</file>
|
||||
<file>transition2.glsl</file>
|
||||
<file>transition3.glsl</file>
|
||||
<file>transition4.glsl</file>
|
||||
<file>cogs2.glsl</file>
|
||||
</gresource>
|
||||
<gresource prefix="/iconscroll">
|
||||
<file>iconscroll.ui</file>
|
||||
</gresource>
|
||||
@@ -247,6 +259,7 @@
|
||||
<file>gears.c</file>
|
||||
<file>gestures.c</file>
|
||||
<file>glarea.c</file>
|
||||
<file>gltransition.c</file>
|
||||
<file>headerbar.c</file>
|
||||
<file>hypertext.c</file>
|
||||
<file>iconscroll.c</file>
|
||||
|
72
demos/gtk-demo/fire.glsl
Normal file
72
demos/gtk-demo/fire.glsl
Normal file
@@ -0,0 +1,72 @@
|
||||
uniform float u_time;
|
||||
uniform sampler2D u_texture1;
|
||||
|
||||
/* 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.0 + 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.0 * 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 = GskTexture(u_texture1,uv);
|
||||
fragColor = mix(vec4(color,1), widget, 1.0-color.x);
|
||||
}
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "gtkfishbowl.h"
|
||||
#include "gtkgears.h"
|
||||
#include "gskshaderpaintable.h"
|
||||
|
||||
const char *const css =
|
||||
".blurred-button {"
|
||||
@@ -149,6 +150,37 @@ create_switch (void)
|
||||
return w;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_paintable (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskShaderPaintable *paintable;
|
||||
gint64 frame_time;
|
||||
|
||||
paintable = GSK_SHADER_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget)));
|
||||
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
|
||||
gsk_shader_paintable_update_time (paintable, 0, frame_time);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_cogs (void)
|
||||
{
|
||||
GtkWidget *picture;
|
||||
GskGLShader *shader;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
shader = gsk_gl_shader_new_from_resource ("/gltransition/cogs2.glsl");
|
||||
paintable = gsk_shader_paintable_new (shader, NULL);
|
||||
picture = gtk_picture_new_for_paintable (paintable);
|
||||
gtk_widget_set_size_request (picture, 150, 75);
|
||||
gtk_widget_add_tick_callback (picture, update_paintable, NULL, NULL);
|
||||
|
||||
return picture;
|
||||
}
|
||||
|
||||
static void
|
||||
mapped (GtkWidget *w)
|
||||
{
|
||||
@@ -185,6 +217,7 @@ static const struct {
|
||||
{ "Gears", create_gears },
|
||||
{ "Switch", create_switch },
|
||||
{ "Menubutton", create_menu_button },
|
||||
{ "Shader", create_cogs },
|
||||
};
|
||||
|
||||
static int selected_widget_type = -1;
|
||||
|
330
demos/gtk-demo/gltransition.c
Normal file
330
demos/gtk-demo/gltransition.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/* OpenGL/Transitions
|
||||
* #Keywords: OpenGL, shader
|
||||
*
|
||||
* Create transitions between pages using a custom fragment shader.
|
||||
* The examples here are taken from gl-transitions.com, and you
|
||||
* can edit the transision code itself on the last page of the stack.
|
||||
*
|
||||
* It also shows some sample fire effects on the buttons.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtkshaderstack.h"
|
||||
#include "gtkshaderbin.h"
|
||||
#include "gtkshadertoy.h"
|
||||
#include "gskshaderpaintable.h"
|
||||
|
||||
static GtkWidget *demo_window = NULL;
|
||||
|
||||
static void
|
||||
close_window (GtkWidget *widget)
|
||||
{
|
||||
/* Reset the state */
|
||||
demo_window = NULL;
|
||||
}
|
||||
|
||||
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 = g_object_get_data (G_OBJECT (button), "the-stack");
|
||||
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
|
||||
|
||||
GBytes *bytes = g_bytes_new_take (text, strlen (text));
|
||||
shader = gsk_gl_shader_new_from_bytes (bytes);
|
||||
|
||||
gtk_shader_stack_set_shader (GTK_SHADER_STACK (stack), shader);
|
||||
|
||||
g_object_unref (shader);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
gtk_widget_hide (button);
|
||||
}
|
||||
|
||||
static void
|
||||
go_back (GtkWidget *button,
|
||||
GtkWidget *stack)
|
||||
{
|
||||
gtk_shader_stack_transition (GTK_SHADER_STACK (stack), FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
go_forward (GtkWidget *button,
|
||||
GtkWidget *stack)
|
||||
{
|
||||
gtk_shader_stack_transition (GTK_SHADER_STACK (stack), TRUE);
|
||||
}
|
||||
|
||||
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 *
|
||||
fire_bin_new (void)
|
||||
{
|
||||
GtkWidget *bin = gtk_shader_bin_new ();
|
||||
static GskGLShader *shader = NULL;
|
||||
|
||||
if (shader == NULL)
|
||||
shader = gsk_gl_shader_new_from_resource ("/gltransition/fire.glsl");
|
||||
|
||||
gtk_shader_bin_add_shader (GTK_SHADER_BIN (bin), shader, GTK_STATE_FLAG_PRELIGHT, GTK_STATE_FLAG_PRELIGHT);
|
||||
|
||||
return bin;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
new_shadertoy (const char *path)
|
||||
{
|
||||
GBytes *shader;
|
||||
GtkWidget *toy;
|
||||
|
||||
toy = gtk_shadertoy_new ();
|
||||
shader = g_resources_lookup_data (path, 0, NULL);
|
||||
gtk_shadertoy_set_image_shader (GTK_SHADERTOY (toy),
|
||||
g_bytes_get_data (shader, NULL));
|
||||
g_bytes_unref (shader);
|
||||
|
||||
return toy;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_paintable (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
GskShaderPaintable *paintable;
|
||||
gint64 frame_time;
|
||||
|
||||
paintable = GSK_SHADER_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget)));
|
||||
frame_time = gdk_frame_clock_get_frame_time (frame_clock);
|
||||
gsk_shader_paintable_update_time (paintable, 0, frame_time);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
make_shader_stack (const char *name,
|
||||
const char *resource_path,
|
||||
GtkWidget *scale,
|
||||
GdkFrameClock *frame_clock)
|
||||
{
|
||||
GtkWidget *stack, *child, *widget, *vbox, *hbox, *bin;
|
||||
GtkWidget *label, *button, *tv;
|
||||
GskGLShader *shader;
|
||||
GObjectClass *class;
|
||||
GParamSpecFloat *pspec;
|
||||
GtkAdjustment *adjustment;
|
||||
GtkTextBuffer *buffer;
|
||||
GBytes *bytes;
|
||||
GtkEventController *controller;
|
||||
GtkCssProvider *provider;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
stack = gtk_shader_stack_new ();
|
||||
shader = gsk_gl_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);
|
||||
|
||||
shader = gsk_gl_shader_new_from_resource ("/gltransition/cogs2.glsl");
|
||||
paintable = gsk_shader_paintable_new (shader, NULL);
|
||||
|
||||
child = gtk_picture_new_for_paintable (paintable);
|
||||
gtk_widget_add_tick_callback (child, update_paintable, NULL, NULL);
|
||||
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 = new_shadertoy ("/shadertoy/neon.glsl");
|
||||
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
|
||||
|
||||
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||
|
||||
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);
|
||||
|
||||
gtk_box_append (GTK_BOX (child), widget);
|
||||
|
||||
gtk_shader_stack_add_child (GTK_SHADER_STACK (stack), child);
|
||||
|
||||
vbox = 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");
|
||||
g_signal_connect (buffer, "changed", G_CALLBACK (text_changed), button);
|
||||
g_object_set_data (G_OBJECT (button), "the-stack", stack);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (apply_text), buffer);
|
||||
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 (vbox), widget);
|
||||
|
||||
gtk_box_append (GTK_BOX (vbox), stack);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_widget_set_halign (hbox, GTK_ALIGN_CENTER);
|
||||
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
|
||||
button = gtk_button_new_from_icon_name ("go-previous");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (go_back), stack);
|
||||
bin = fire_bin_new ();
|
||||
gtk_shader_bin_set_child (GTK_SHADER_BIN (bin), button);
|
||||
gtk_box_append (GTK_BOX (hbox), bin);
|
||||
|
||||
button = gtk_button_new_from_icon_name ("go-next");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (go_forward), stack);
|
||||
bin = fire_bin_new ();
|
||||
gtk_shader_bin_set_child (GTK_SHADER_BIN (bin), button);
|
||||
gtk_box_append (GTK_BOX (hbox), bin);
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_gltransition_window (GtkWidget *do_widget)
|
||||
{
|
||||
GtkWidget *window, *headerbar, *scale, *grid;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
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), 800, 600);
|
||||
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_widget_realize (window);
|
||||
frame_clock = gtk_widget_get_frame_clock (window);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
make_shader_stack ("Wind", "/gltransition/transition1.glsl", scale, frame_clock),
|
||||
0, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
make_shader_stack ("Radial", "/gltransition/transition2.glsl", scale, frame_clock),
|
||||
1, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
make_shader_stack ("Crosswarp", "/gltransition/transition3.glsl", scale, frame_clock),
|
||||
0, 1, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
make_shader_stack ("Kaleidoscope", "/gltransition/transition4.glsl", scale, frame_clock),
|
||||
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;
|
||||
}
|
349
demos/gtk-demo/gskshaderpaintable.c
Normal file
349
demos/gtk-demo/gskshaderpaintable.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gskshaderpaintable.h"
|
||||
|
||||
/**
|
||||
* SECTION:gskshaderpaintable
|
||||
* @Short_description: Drawing with shaders
|
||||
* @Title: GskShaderPaintable
|
||||
* @see_also: #GdkPaintable
|
||||
*
|
||||
* GskShaderPaintable is an implementation of the #GdkPaintable interface
|
||||
* that uses a #GskGLShader to create pixels.
|
||||
*
|
||||
* You can set the uniform data that the shader needs for rendering
|
||||
* using gsk_shader_paintable_set_uniform_data(). This function can
|
||||
* be called repeatedly to change the uniform data for the next
|
||||
* snapshot.
|
||||
*
|
||||
* Commonly, time is passed to shaders as a float uniform containing
|
||||
* the elapsed time in seconds. The convenience API
|
||||
* gsk_shader_paintable_update_time() can be called from a #GtkTickCallback
|
||||
* to update the time based on the frame time of the frame clock.
|
||||
*/
|
||||
|
||||
|
||||
struct _GskShaderPaintable
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GskGLShader *shader;
|
||||
GBytes *uniform_data;
|
||||
|
||||
gint64 start_time;
|
||||
};
|
||||
|
||||
struct _GskShaderPaintableClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SHADER,
|
||||
PROP_UNIFORM_DATA,
|
||||
|
||||
N_PROPS,
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (paintable);
|
||||
|
||||
/* FIXME: We have to add a pointless extra child here to
|
||||
* keep GtkSnapshot from blowing up. We really want n_children = 0,
|
||||
* but then we would pop() 0 times, and... no pop, no node.
|
||||
*/
|
||||
gtk_snapshot_push_gl_shader (snapshot, self->shader, &GRAPHENE_RECT_INIT(0, 0, width, height), g_bytes_ref (self->uniform_data), 1);
|
||||
gtk_snapshot_append_color (snapshot, &(GdkRGBA){1.0, 0.5, 0.6, 1.0}, &GRAPHENE_RECT_INIT(0, 0, width, height));
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot = gsk_shader_paintable_paintable_snapshot;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GskShaderPaintable, gsk_shader_paintable, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gsk_shader_paintable_paintable_init))
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SHADER:
|
||||
gsk_shader_paintable_set_shader (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_UNIFORM_DATA:
|
||||
gsk_shader_paintable_set_uniform_data (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SHADER:
|
||||
g_value_set_object (value, self->shader);
|
||||
break;
|
||||
|
||||
case PROP_UNIFORM_DATA:
|
||||
g_value_set_boxed (value, self->uniform_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_finalize (GObject *object)
|
||||
{
|
||||
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (object);
|
||||
|
||||
g_clear_pointer (&self->uniform_data, g_bytes_unref);
|
||||
g_clear_object (&self->shader);
|
||||
|
||||
G_OBJECT_CLASS (gsk_shader_paintable_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_class_init (GskShaderPaintableClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = gsk_shader_paintable_get_property;
|
||||
gobject_class->set_property = gsk_shader_paintable_set_property;
|
||||
gobject_class->finalize = gsk_shader_paintable_finalize;
|
||||
|
||||
properties[PROP_SHADER] =
|
||||
g_param_spec_object ("shader", "Shader", "The shader",
|
||||
GSK_TYPE_GL_SHADER,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_UNIFORM_DATA] =
|
||||
g_param_spec_boxed ("uniform-data", "Uniform data", "The uniform data",
|
||||
G_TYPE_BYTES,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_paintable_init (GskShaderPaintable *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shader_paintable_new:
|
||||
* @shader: (transfer full) (nullable): the shader to use
|
||||
* @data: (transfer full) (nullable): uniform data
|
||||
*
|
||||
* Creates a paintable that uses the @shader to create
|
||||
* pixels. The shader must not require input textures.
|
||||
* If @data is %NULL, all uniform values are set to zero.
|
||||
*
|
||||
* Returns: (transfer full): a new #GskShaderPaintable
|
||||
*/
|
||||
GdkPaintable *
|
||||
gsk_shader_paintable_new (GskGLShader *shader,
|
||||
GBytes *data)
|
||||
{
|
||||
GdkPaintable *ret;
|
||||
|
||||
g_return_val_if_fail (shader == NULL || GSK_IS_GL_SHADER (shader), NULL);
|
||||
|
||||
if (shader && !data)
|
||||
{
|
||||
int size = gsk_gl_shader_get_args_size (shader);
|
||||
data = g_bytes_new_take (g_new0 (guchar, size), size);
|
||||
}
|
||||
|
||||
ret = g_object_new (GSK_TYPE_SHADER_PAINTABLE,
|
||||
"shader", shader,
|
||||
"uniform-data", data,
|
||||
NULL);
|
||||
|
||||
g_clear_object (&shader);
|
||||
g_clear_pointer (&data, g_bytes_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shader_paintable_set_shader:
|
||||
* @self: a #GskShaderPaintable
|
||||
* @shader: the #GskGLShader to use
|
||||
*
|
||||
* Sets the shader that the paintable will use
|
||||
* to create pixels. The shader must not require
|
||||
* input textures.
|
||||
*/
|
||||
void
|
||||
gsk_shader_paintable_set_shader (GskShaderPaintable *self,
|
||||
GskGLShader *shader)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_PAINTABLE (self));
|
||||
g_return_if_fail (shader == NULL || GSK_IS_GL_SHADER (shader));
|
||||
g_return_if_fail (shader == NULL || gsk_gl_shader_get_n_required_textures (shader) == 0);
|
||||
|
||||
if (!g_set_object (&self->shader, shader))
|
||||
return;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHADER]);
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
|
||||
g_clear_pointer (&self->uniform_data, g_bytes_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shader_paintable_get_shader:
|
||||
* @self: a #GskShaderPaintable
|
||||
*
|
||||
* Returns the shader that the paintable is using.
|
||||
*
|
||||
* Returns: (transfer none): the #GskGLShader that is used
|
||||
*/
|
||||
GskGLShader *
|
||||
gsk_shader_paintable_get_shader (GskShaderPaintable *self)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_SHADER_PAINTABLE (self), NULL);
|
||||
|
||||
return self->shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shader_paintable_set_uniform_data:
|
||||
* @self: a #GskShaderPaintable
|
||||
* @data: Data block with uniform data for the shader
|
||||
*
|
||||
* Sets the uniform data that will be passed to the
|
||||
* shader when rendering. The @data will typically
|
||||
* be produced by a #GskUniformDataBuilder.
|
||||
*
|
||||
* Note that the @data should be considered immutable
|
||||
* after it has been passed to this function.
|
||||
*/
|
||||
void
|
||||
gsk_shader_paintable_set_uniform_data (GskShaderPaintable *self,
|
||||
GBytes *data)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_PAINTABLE (self));
|
||||
g_return_if_fail (data == NULL || g_bytes_get_size (data) == gsk_gl_shader_get_args_size (self->shader));
|
||||
|
||||
g_clear_pointer (&self->uniform_data, g_bytes_unref);
|
||||
if (data)
|
||||
self->uniform_data = g_bytes_ref (data);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UNIFORM_DATA]);
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shader_paintable_get_uniform_data:
|
||||
* @self: a #GskShaderPaintable
|
||||
*
|
||||
* Returns the uniform data set with
|
||||
* gsk_shader_paintable_get_uniform_data().
|
||||
*
|
||||
* Returns: (transfer none): the uniform data
|
||||
*/
|
||||
GBytes *
|
||||
gsk_shader_paintable_get_uniform_data (GskShaderPaintable *self)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_SHADER_PAINTABLE (self), NULL);
|
||||
|
||||
return self->uniform_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shader_paintable_update_time:
|
||||
* @self: a #GskShaderPaintable
|
||||
* @time_idx: the index of the uniform for time in seconds as float
|
||||
* @frame_time: the current frame time, as returned by #GdkFrameClock
|
||||
*
|
||||
* This function is a convenience wrapper for
|
||||
* gsk_shader_paintable_set_uniform_data() that leaves all
|
||||
* uniform values unchanged, except for the uniform with
|
||||
* index @time_idx, which will be set to the elapsed time
|
||||
* in seconds, since the first call to this function.
|
||||
*
|
||||
* This function is usually called from a #GtkTickCallback.
|
||||
*/
|
||||
void
|
||||
gsk_shader_paintable_update_time (GskShaderPaintable *self,
|
||||
int time_idx,
|
||||
gint64 frame_time)
|
||||
{
|
||||
int size;
|
||||
int offset;
|
||||
guchar *data;
|
||||
float time;
|
||||
GBytes *uniform_data;
|
||||
|
||||
size = gsk_gl_shader_get_args_size (self->shader);
|
||||
offset = gsk_gl_shader_get_uniform_offset (self->shader, time_idx);
|
||||
|
||||
data = g_new0 (guchar, size);
|
||||
memcpy (data, g_bytes_get_data (self->uniform_data, NULL), size);
|
||||
|
||||
if (self->start_time == 0)
|
||||
self->start_time = frame_time;
|
||||
|
||||
time = (frame_time - self->start_time) / (float)G_TIME_SPAN_SECOND;
|
||||
*(float*)(data + offset) = time;
|
||||
|
||||
uniform_data = g_bytes_new_take (data, size);
|
||||
|
||||
gsk_shader_paintable_set_uniform_data (self, uniform_data);
|
||||
|
||||
g_bytes_unref (uniform_data);
|
||||
}
|
53
demos/gtk-demo/gskshaderpaintable.h
Normal file
53
demos/gtk-demo/gskshaderpaintable.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GSK_SHADER_PAINTABLE_H__
|
||||
#define __GSK_SHADER_PAINTABLE_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gsk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_SHADER_PAINTABLE (gsk_shader_paintable_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GskShaderPaintable, gsk_shader_paintable, GSK, SHADER_PAINTABLE, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkPaintable * gsk_shader_paintable_new (GskGLShader *shader,
|
||||
GBytes *data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_shader_paintable_get_shader (GskShaderPaintable *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_paintable_set_shader (GskShaderPaintable *self,
|
||||
GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GBytes * gsk_shader_paintable_get_uniform_data (GskShaderPaintable *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_paintable_set_uniform_data (GskShaderPaintable *self,
|
||||
GBytes *data);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_paintable_update_time (GskShaderPaintable *self,
|
||||
int time_idx,
|
||||
gint64 frame_time);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_SHADER_PAINTABLE_H__ */
|
241
demos/gtk-demo/gtkshaderbin.c
Normal file
241
demos/gtk-demo/gtkshaderbin.c
Normal file
@@ -0,0 +1,241 @@
|
||||
#include "gtkshaderbin.h"
|
||||
|
||||
typedef struct {
|
||||
GskGLShader *shader;
|
||||
GtkStateFlags state;
|
||||
GtkStateFlags state_mask;
|
||||
gboolean compiled;
|
||||
gboolean compiled_ok;
|
||||
} ShaderInfo;
|
||||
|
||||
struct _GtkShaderBin
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkWidget *child;
|
||||
ShaderInfo *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));
|
||||
ShaderInfo *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;
|
||||
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)
|
||||
{
|
||||
if (!self->active_shader->compiled)
|
||||
{
|
||||
GtkNative *native = gtk_widget_get_native (widget);
|
||||
GskRenderer *renderer = gtk_native_get_renderer (native);
|
||||
GError *error = NULL;
|
||||
|
||||
self->active_shader->compiled = TRUE;
|
||||
self->active_shader->compiled_ok =
|
||||
gsk_gl_shader_try_compile_for (self->active_shader->shader,
|
||||
renderer, &error);
|
||||
if (!self->active_shader->compiled_ok)
|
||||
{
|
||||
g_warning ("GtkShaderBin failed to compile shader: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
if (self->active_shader->compiled_ok)
|
||||
{
|
||||
gtk_snapshot_push_gl_shader (snapshot, self->active_shader->shader,
|
||||
&GRAPHENE_RECT_INIT(0, 0, width, height),
|
||||
gsk_gl_shader_format_args (self->active_shader->shader,
|
||||
"u_time", &self->time,
|
||||
NULL),
|
||||
1);
|
||||
gtk_widget_snapshot_child (widget, self->child, snapshot);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-shader fallback */
|
||||
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);
|
||||
}
|
22
demos/gtk-demo/gtkshaderbin.h
Normal file
22
demos/gtk-demo/gtkshaderbin.h
Normal file
@@ -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__ */
|
353
demos/gtk-demo/gtkshaderstack.c
Normal file
353
demos/gtk-demo/gtkshaderstack.c
Normal file
@@ -0,0 +1,353 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
if (self->next != -1)
|
||||
self->current = self->next;
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_shader_stack_transition (GtkShaderStack *self,
|
||||
gboolean forward)
|
||||
{
|
||||
stop_transition (self);
|
||||
|
||||
self->backwards = !forward;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
GtkNative *native = gtk_widget_get_native (widget);
|
||||
GskRenderer *renderer = gtk_native_get_renderer (native);
|
||||
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;
|
||||
}
|
||||
|
||||
if (gsk_gl_shader_try_compile_for (self->shader,
|
||||
renderer, NULL))
|
||||
{
|
||||
gtk_snapshot_push_gl_shader (snapshot,
|
||||
self->shader,
|
||||
&GRAPHENE_RECT_INIT(0, 0, width, height),
|
||||
gsk_gl_shader_format_args (self->shader,
|
||||
"progress", &progress,
|
||||
NULL),
|
||||
2);
|
||||
|
||||
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 */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Non-shader fallback */
|
||||
gtk_widget_snapshot_child (widget, current, snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
21
demos/gtk-demo/gtkshaderstack.h
Normal file
21
demos/gtk-demo/gtkshaderstack.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#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);
|
||||
void gtk_shader_stack_transition (GtkShaderStack *self,
|
||||
gboolean forward);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SHADER_STACK_H__ */
|
@@ -56,13 +56,15 @@ const char *fragment_prefix =
|
||||
"uniform float iSampleRate; // sound sample rate (i.e., 44100)\n"
|
||||
"\n"
|
||||
"in vec2 fragCoord;\n"
|
||||
"out vec4 fragColor;\n";
|
||||
"out vec4 vFragColor;\n";
|
||||
|
||||
|
||||
// Fragment shader suffix
|
||||
const char *fragment_suffix =
|
||||
" void main() {\n"
|
||||
" mainImage(fragColor, fragCoord);\n"
|
||||
" vec4 c;\n"
|
||||
" mainImage(c, fragCoord);\n"
|
||||
" vFragColor = c;\n"
|
||||
" }\n";
|
||||
|
||||
typedef struct {
|
||||
|
@@ -32,6 +32,7 @@ demos = files([
|
||||
'gears.c',
|
||||
'gestures.c',
|
||||
'glarea.c',
|
||||
'gltransition.c',
|
||||
'headerbar.c',
|
||||
'hypertext.c',
|
||||
'iconscroll.c',
|
||||
@@ -102,7 +103,10 @@ extra_demo_sources = files(['main.c',
|
||||
'gtkfishbowl.c',
|
||||
'fontplane.c',
|
||||
'gtkgears.c',
|
||||
'gtkshaderbin.c',
|
||||
'gtkshadertoy.c',
|
||||
'gtkshaderstack.c',
|
||||
'gskshaderpaintable.c',
|
||||
'puzzlepiece.c',
|
||||
'bluroverlay.c',
|
||||
'demoimage.c',
|
||||
|
33
demos/gtk-demo/transition1.glsl
Normal file
33
demos/gtk-demo/transition1.glsl
Normal file
@@ -0,0 +1,33 @@
|
||||
uniform float progress;
|
||||
uniform sampler2D u_texture1;
|
||||
uniform sampler2D u_texture2;
|
||||
|
||||
vec4 getFromColor (vec2 uv) {
|
||||
return GskTexture(u_texture1, uv);
|
||||
}
|
||||
|
||||
vec4 getToColor (vec2 uv) {
|
||||
return GskTexture(u_texture2, uv);
|
||||
}
|
||||
|
||||
// Source: https://gl-transitions.com/editor/wind
|
||||
// Author: gre
|
||||
// License: MIT
|
||||
|
||||
const 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);
|
||||
}
|
34
demos/gtk-demo/transition2.glsl
Normal file
34
demos/gtk-demo/transition2.glsl
Normal file
@@ -0,0 +1,34 @@
|
||||
uniform float progress;
|
||||
uniform sampler2D u_texture1;
|
||||
uniform sampler2D u_texture2;
|
||||
|
||||
vec4 getFromColor (vec2 uv) {
|
||||
return GskTexture(u_texture1, uv);
|
||||
}
|
||||
|
||||
vec4 getToColor (vec2 uv) {
|
||||
return GskTexture(u_texture2, uv);
|
||||
}
|
||||
|
||||
// Source: https://gl-transitions.com/editor/Radial
|
||||
// License: MIT
|
||||
// Author: Xaychru
|
||||
|
||||
const 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);
|
||||
}
|
27
demos/gtk-demo/transition3.glsl
Normal file
27
demos/gtk-demo/transition3.glsl
Normal file
@@ -0,0 +1,27 @@
|
||||
uniform float progress;
|
||||
uniform sampler2D u_texture1;
|
||||
uniform sampler2D u_texture2;
|
||||
|
||||
vec4 getFromColor (vec2 uv) {
|
||||
return GskTexture(u_texture1, uv);
|
||||
}
|
||||
|
||||
vec4 getToColor (vec2 uv) {
|
||||
return GskTexture(u_texture2, 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);
|
||||
}
|
41
demos/gtk-demo/transition4.glsl
Normal file
41
demos/gtk-demo/transition4.glsl
Normal file
@@ -0,0 +1,41 @@
|
||||
uniform float progress;
|
||||
uniform sampler2D u_texture1;
|
||||
uniform sampler2D u_texture2;
|
||||
|
||||
vec4 getFromColor (vec2 uv) {
|
||||
return GskTexture(u_texture1, uv);
|
||||
}
|
||||
|
||||
vec4 getToColor (vec2 uv) {
|
||||
return GskTexture(u_texture2, uv);
|
||||
}
|
||||
|
||||
// Source: https://gl-transitions.com/editor/kaleidoscope
|
||||
// Author: nwoeanhinnogaehr
|
||||
// License: MIT
|
||||
|
||||
const float speed = 1.0;
|
||||
const float angle = 1.0;
|
||||
const 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);
|
||||
}
|
@@ -20,6 +20,7 @@
|
||||
<xi:include href="xml/GskRenderNode.xml" />
|
||||
<xi:include href="xml/GskRoundedRect.xml" />
|
||||
<xi:include href="xml/GskTransform.xml" />
|
||||
<xi:include href="xml/GskGLShader.xml" />
|
||||
</reference>
|
||||
|
||||
<index id="api-index-full">
|
||||
|
@@ -48,6 +48,7 @@ GskShadowNode
|
||||
GskTextNode
|
||||
GskTextureNode
|
||||
GskTransformNode
|
||||
GskGLShaderNode
|
||||
gsk_render_node_ref
|
||||
gsk_render_node_unref
|
||||
GskRenderNodeType
|
||||
@@ -152,6 +153,12 @@ gsk_blur_node_get_radius
|
||||
gsk_debug_node_new
|
||||
gsk_debug_node_get_child
|
||||
gsk_debug_node_get_message
|
||||
gsk_gl_shader_node_new
|
||||
gsk_gl_shader_node_get_fallback_child
|
||||
gsk_gl_shader_node_get_n_children
|
||||
gsk_gl_shader_node_get_child
|
||||
gsk_gl_shader_node_get_uniform_data
|
||||
gsk_gl_shader_node_get_shader
|
||||
<SUBSECTION Standard>
|
||||
GSK_IS_RENDER_NODE
|
||||
GSK_RENDER_NODE
|
||||
@@ -177,6 +184,7 @@ GSK_TYPE_SHADOW_NODE
|
||||
GSK_TYPE_TEXT_NODE
|
||||
GSK_TYPE_TEXTURE_NODE
|
||||
GSK_TYPE_TRANSFORM_NODE
|
||||
GSK_TYPE_GLSHADER_NODE
|
||||
GskRenderNodeClass
|
||||
gsk_blend_node_get_type
|
||||
gsk_blur_node_get_type
|
||||
@@ -202,6 +210,7 @@ gsk_shadow_node_get_type
|
||||
gsk_text_node_get_type
|
||||
gsk_texture_node_get_type
|
||||
gsk_transform_node_get_type
|
||||
gsk_gl_shader_node_get_type
|
||||
GSK_TYPE_BLEND_MODE
|
||||
<SUBSECTION Standard>
|
||||
gsk_serialization_error_quark
|
||||
@@ -266,3 +275,44 @@ gsk_transform_get_type
|
||||
gsk_transform_new
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>GskGLShader</FILE>
|
||||
GskGLShader
|
||||
gsk_gl_shader_new_from_bytes
|
||||
gsk_gl_shader_new_from_resource
|
||||
gsk_gl_shader_get_bytes
|
||||
gsk_gl_shader_get_n_required_textures
|
||||
gsk_gl_shader_get_n_uniforms
|
||||
gsk_gl_shader_get_uniform_name
|
||||
gsk_gl_shader_find_uniform_by_name
|
||||
gsk_gl_shader_get_uniform_type
|
||||
gsk_gl_shader_get_uniform_offset
|
||||
gsk_gl_shader_get_args_size
|
||||
|
||||
<SUBSECTION Uniform Data>
|
||||
gsk_gl_shader_get_arg_float
|
||||
gsk_gl_shader_get_arg_int
|
||||
gsk_gl_shader_get_arg_uint
|
||||
gsk_gl_shader_get_arg_bool
|
||||
gsk_gl_shader_get_arg_vec2
|
||||
gsk_gl_shader_get_arg_vec3
|
||||
gsk_gl_shader_get_arg_vec4
|
||||
gsk_gl_shader_format_args_va
|
||||
gsk_gl_shader_format_args
|
||||
|
||||
<SUBSECTION Shader Args Builder>
|
||||
GskShaderArgsBuilder
|
||||
|
||||
gsk_gl_shader_build_args
|
||||
gsk_shader_args_builder_finish
|
||||
gsk_shader_args_builder_free
|
||||
gsk_shader_args_builder_copy
|
||||
|
||||
gsk_shader_args_builder_set_float
|
||||
gsk_shader_args_builder_set_int
|
||||
gsk_shader_args_builder_set_uint
|
||||
gsk_shader_args_builder_set_bool
|
||||
gsk_shader_args_builder_set_vec2
|
||||
gsk_shader_args_builder_set_vec3
|
||||
gsk_shader_args_builder_set_vec4
|
||||
</SECTION>
|
||||
|
@@ -1,2 +1,3 @@
|
||||
gsk_render_node_get_type
|
||||
gsk_renderer_get_type
|
||||
gsk_gl_shader_get_type
|
||||
|
@@ -4311,6 +4311,7 @@ gtk_snapshot_push_blend
|
||||
gtk_snapshot_push_blur
|
||||
gtk_snapshot_push_shadow
|
||||
gtk_snapshot_push_debug
|
||||
gtk_snapshot_push_gl_shader
|
||||
gtk_snapshot_pop
|
||||
gtk_snapshot_save
|
||||
gtk_snapshot_restore
|
||||
|
@@ -258,6 +258,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
|
||||
/* Fallbacks (=> leaf for now */
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
@@ -847,6 +848,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GL_SHADER_NODE:
|
||||
default:
|
||||
break; /* Fallback */
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglrenderer.h"
|
||||
#include "gskglrendererprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskenums.h"
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "gskglnodesampleprivate.h"
|
||||
#include "gsktransform.h"
|
||||
#include "glutilsprivate.h"
|
||||
#include "gskglshaderprivate.h"
|
||||
|
||||
#include "gskprivate.h"
|
||||
|
||||
@@ -64,6 +65,11 @@
|
||||
glGetUniformLocation(program_ptr->id, "u_" #uniform_basename);\
|
||||
}G_STMT_END
|
||||
|
||||
static Program *gsk_gl_renderer_lookup_custom_program (GskGLRenderer *self,
|
||||
GskGLShader *shader);
|
||||
static Program *gsk_gl_renderer_create_custom_program (GskGLRenderer *self,
|
||||
GskGLShader *shader);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FORCE_OFFSCREEN = 1 << 0,
|
||||
@@ -130,6 +136,12 @@ print_render_node_tree (GskRenderNode *root, int level)
|
||||
print_render_node_tree (gsk_shadow_node_get_child (root), level + 1);
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
g_print ("%*s GL Shader\n", level * INDENT, " ");
|
||||
for (i = 0; i < gsk_gl_shader_node_get_n_children (root); i++)
|
||||
print_render_node_tree (gsk_gl_shader_node_get_child (root, i), level + 1);
|
||||
break;
|
||||
|
||||
case GSK_TEXTURE_NODE:
|
||||
g_print ("%*s Texture %p\n", level * INDENT, " ", gsk_texture_node_get_texture (root));
|
||||
break;
|
||||
@@ -495,6 +507,40 @@ struct _GskGLRendererClass
|
||||
|
||||
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
|
||||
|
||||
static void
|
||||
init_shader_builder (GskGLRenderer *self,
|
||||
GskGLShaderBuilder *shader_builder)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS))
|
||||
shader_builder->debugging = TRUE;
|
||||
#endif
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->gl_context))
|
||||
{
|
||||
gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GLES);
|
||||
shader_builder->gles = TRUE;
|
||||
}
|
||||
else if (gdk_gl_context_is_legacy (self->gl_context))
|
||||
{
|
||||
int maj, min;
|
||||
|
||||
gdk_gl_context_get_version (self->gl_context, &maj, &min);
|
||||
|
||||
if (maj == 3)
|
||||
gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3_LEGACY);
|
||||
else
|
||||
gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL2_LEGACY);
|
||||
|
||||
shader_builder->legacy = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3);
|
||||
shader_builder->gl3 = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void G_GNUC_UNUSED
|
||||
add_rect_ops (RenderOpBuilder *builder,
|
||||
const graphene_rect_t *r)
|
||||
@@ -1006,6 +1052,178 @@ render_texture_node (GskGLRenderer *self,
|
||||
}
|
||||
}
|
||||
|
||||
static Program *
|
||||
compile_glshader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error)
|
||||
{
|
||||
GskGLShaderBuilder shader_builder;
|
||||
const char *shader_source;
|
||||
gsize shader_source_len;
|
||||
int n_uniforms;
|
||||
const GskGLUniform *uniforms;
|
||||
GBytes *bytes;
|
||||
int n_required_textures = gsk_gl_shader_get_n_required_textures (shader);
|
||||
int program_id;
|
||||
Program *program;
|
||||
|
||||
bytes = gsk_gl_shader_get_bytes (shader);
|
||||
shader_source = g_bytes_get_data (bytes, &shader_source_len);
|
||||
uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms);
|
||||
|
||||
if (n_uniforms > G_N_ELEMENTS (program->glshader.args_locations))
|
||||
{
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
"GLShaderNode supports max %d custom uniforms", (int)G_N_ELEMENTS (program->glshader.args_locations));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (n_required_textures > G_N_ELEMENTS (program->glshader.texture_locations))
|
||||
{
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
"GLShaderNode supports max %d texture sources", (int)(G_N_ELEMENTS (program->glshader.texture_locations)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gsk_gl_shader_builder_init (&shader_builder,
|
||||
"/org/gtk/libgsk/glsl/preamble.glsl",
|
||||
"/org/gtk/libgsk/glsl/preamble.vs.glsl",
|
||||
"/org/gtk/libgsk/glsl/preamble.fs.glsl");
|
||||
|
||||
init_shader_builder (self, &shader_builder);
|
||||
program_id = gsk_gl_shader_builder_create_program (&shader_builder,
|
||||
"/org/gtk/libgsk/glsl/custom.glsl",
|
||||
shader_source, shader_source_len,
|
||||
error);
|
||||
gsk_gl_shader_builder_finish (&shader_builder);
|
||||
|
||||
if (program_id < 0)
|
||||
return NULL;
|
||||
|
||||
program = gsk_gl_renderer_create_custom_program (self, shader);
|
||||
|
||||
program->id = program_id;
|
||||
INIT_COMMON_UNIFORM_LOCATION (program, alpha);
|
||||
INIT_COMMON_UNIFORM_LOCATION (program, clip_rect);
|
||||
INIT_COMMON_UNIFORM_LOCATION (program, viewport);
|
||||
INIT_COMMON_UNIFORM_LOCATION (program, projection);
|
||||
INIT_COMMON_UNIFORM_LOCATION (program, modelview);
|
||||
program->glshader.size_location = glGetUniformLocation(program->id, "u_size");
|
||||
program->glshader.texture_locations[0] = glGetUniformLocation(program->id, "u_texture1");
|
||||
program->glshader.texture_locations[1] = glGetUniformLocation(program->id, "u_texture2");
|
||||
program->glshader.texture_locations[2] = glGetUniformLocation(program->id, "u_texture3");
|
||||
program->glshader.texture_locations[3] = glGetUniformLocation(program->id, "u_texture4");
|
||||
|
||||
/* We use u_textue1 for the texture 0 in the glshaders, so alias it here so we can use the regular setters */
|
||||
program->source_location = program->glshader.texture_locations[0];
|
||||
|
||||
for (int i = 0; i < G_N_ELEMENTS (program->glshader.args_locations); i++)
|
||||
{
|
||||
if (i < n_uniforms)
|
||||
{
|
||||
program->glshader.args_locations[i] = glGetUniformLocation(program->id, uniforms[i].name);
|
||||
/* This isn't necessary a hard error, you might declare uniforms that are not actually
|
||||
always used, for instance if you have an "API" in uniforms for multiple shaders. */
|
||||
if (program->glshader.args_locations[i] == -1)
|
||||
g_debug ("Declared uniform `%s` not found in GskGLShader", uniforms[i].name);
|
||||
}
|
||||
else
|
||||
program->glshader.args_locations[i] = -1;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_render_try_compile_gl_shader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error)
|
||||
{
|
||||
Program *program;
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
/* Maybe we tried to compile it already? */
|
||||
program = gsk_gl_renderer_lookup_custom_program (self, shader);
|
||||
if (program != NULL)
|
||||
{
|
||||
if (program->id > 0)
|
||||
return TRUE;
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_error_copy (program->glshader.compile_error));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
program = compile_glshader (self, shader, error);
|
||||
return program != NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_gl_shader_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
|
||||
Program *program = gsk_gl_renderer_lookup_custom_program (self, shader);
|
||||
int n_children = gsk_gl_shader_node_get_n_children (node);
|
||||
|
||||
if (program == NULL)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
program = compile_glshader (self, shader, &error);
|
||||
if (program == NULL)
|
||||
{
|
||||
/* We create the program anyway (in a failed state), so that any compiler warnings or other are only reported once */
|
||||
program = gsk_gl_renderer_create_custom_program (self, shader);
|
||||
program->id = -1;
|
||||
program->glshader.compile_error = error;
|
||||
|
||||
g_warning ("Failed to compile gl shader: %s", error->message);
|
||||
}
|
||||
}
|
||||
|
||||
if (program->id >= 0 && n_children <= G_N_ELEMENTS (program->glshader.texture_locations))
|
||||
{
|
||||
GBytes *args;
|
||||
TextureRegion regions[4];
|
||||
gboolean is_offscreen[4];
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
|
||||
if (!add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
child,
|
||||
®ions[i], &is_offscreen[i],
|
||||
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY))
|
||||
return;
|
||||
}
|
||||
|
||||
args = gsk_gl_shader_node_get_args (node);
|
||||
ops_set_program (builder, program);
|
||||
|
||||
ops_set_gl_shader_args (builder, shader, node->bounds.size.width, node->bounds.size.height, g_bytes_get_data (args, NULL));
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
ops_set_texture (builder, regions[i].texture_id);
|
||||
else
|
||||
ops_set_extra_texture (builder, regions[i].texture_id, i);
|
||||
}
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
static GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
|
||||
ops_set_program (builder, &self->programs->color_program);
|
||||
ops_set_color (builder, &pink);
|
||||
load_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns TRUE is applying transform to bounds
|
||||
* yields an axis-aligned rectangle
|
||||
*/
|
||||
@@ -2671,6 +2889,17 @@ apply_source_texture_op (const Program *program,
|
||||
glBindTexture (GL_TEXTURE_2D, op->texture_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_source_extra_texture_op (const Program *program,
|
||||
const OpExtraTexture *op)
|
||||
{
|
||||
g_assert(op->texture_id != 0);
|
||||
OP_PRINT (" -> New extra texture %d: %d", op->idx, op->texture_id);
|
||||
glUniform1i (program->glshader.texture_locations[op->idx], op->idx);
|
||||
glActiveTexture (GL_TEXTURE0 + op->idx);
|
||||
glBindTexture (GL_TEXTURE_2D, op->texture_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_color_matrix_op (const Program *program,
|
||||
const OpColorMatrix *op)
|
||||
@@ -2815,6 +3044,51 @@ apply_border_op (const Program *program,
|
||||
glUniform4fv (program->border.outline_rect_location, 3, (float *)&op->outline.bounds);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_gl_shader_args_op (const Program *program,
|
||||
const OpGLShader *op)
|
||||
{
|
||||
int n_uniforms, i;
|
||||
const GskGLUniform *uniforms;
|
||||
|
||||
OP_PRINT (" -> GL Shader Args");
|
||||
|
||||
glUniform2fv (program->glshader.size_location, 1, op->size);
|
||||
|
||||
uniforms = gsk_gl_shader_get_uniforms (op->shader, &n_uniforms);
|
||||
for (i = 0; i < n_uniforms; i++)
|
||||
{
|
||||
const GskGLUniform *u = &uniforms[i];
|
||||
const guchar *data = op->uniform_data + u->offset;
|
||||
|
||||
switch (u->type)
|
||||
{
|
||||
default:
|
||||
case GSK_GL_UNIFORM_TYPE_NONE:
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_FLOAT:
|
||||
glUniform1fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_INT:
|
||||
glUniform1iv (program->glshader.args_locations[i], 1, (const gint32 *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_UINT:
|
||||
case GSK_GL_UNIFORM_TYPE_BOOL:
|
||||
glUniform1uiv (program->glshader.args_locations[i], 1, (const guint32 *) data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_VEC2:
|
||||
glUniform2fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_VEC3:
|
||||
glUniform3fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_VEC4:
|
||||
glUniform4fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_border_width_op (const Program *program,
|
||||
const OpBorder *op)
|
||||
@@ -2886,6 +3160,32 @@ gsk_gl_renderer_dispose (GObject *gobject)
|
||||
G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
program_init (Program *program)
|
||||
{
|
||||
program->index = -1;
|
||||
program->state.opacity = 1.0f;
|
||||
}
|
||||
|
||||
static void
|
||||
program_finalize (Program *program)
|
||||
{
|
||||
if (program->id > 0)
|
||||
glDeleteProgram (program->id);
|
||||
if (program->index == -1 &&
|
||||
program->glshader.compile_error != NULL)
|
||||
g_error_free (program->glshader.compile_error);
|
||||
|
||||
gsk_transform_unref (program->state.modelview);
|
||||
}
|
||||
|
||||
static void
|
||||
program_free (Program *program)
|
||||
{
|
||||
program_finalize (program);
|
||||
g_free (program);
|
||||
}
|
||||
|
||||
static GskGLRendererPrograms *
|
||||
gsk_gl_renderer_programs_new (void)
|
||||
{
|
||||
@@ -2895,9 +3195,11 @@ gsk_gl_renderer_programs_new (void)
|
||||
programs = g_new0 (GskGLRendererPrograms, 1);
|
||||
programs->ref_count = 1;
|
||||
for (i = 0; i < GL_N_PROGRAMS; i ++)
|
||||
{
|
||||
programs->state[i].opacity = 1.0f;
|
||||
}
|
||||
program_init (&programs->programs[i]);
|
||||
|
||||
/* We use direct hash for performance, not string hash on the source, because we assume each caller
|
||||
* reuses a single GskGLShader for all uses and different callers will use different source content. */
|
||||
programs->custom_programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify)g_object_unref, (GDestroyNotify)program_free);
|
||||
|
||||
return programs;
|
||||
}
|
||||
@@ -2918,15 +3220,33 @@ gsk_gl_renderer_programs_unref (GskGLRendererPrograms *programs)
|
||||
if (programs->ref_count == 0)
|
||||
{
|
||||
for (i = 0; i < GL_N_PROGRAMS; i ++)
|
||||
{
|
||||
if (programs->programs[i].id > 0)
|
||||
glDeleteProgram (programs->programs[i].id);
|
||||
gsk_transform_unref (programs->state[i].modelview);
|
||||
}
|
||||
program_finalize (&programs->programs[i]);
|
||||
|
||||
g_hash_table_destroy (programs->custom_programs);
|
||||
g_free (programs);
|
||||
}
|
||||
}
|
||||
|
||||
static Program *
|
||||
gsk_gl_renderer_lookup_custom_program (GskGLRenderer *self,
|
||||
GskGLShader *shader)
|
||||
{
|
||||
return g_hash_table_lookup (self->programs->custom_programs, shader);
|
||||
}
|
||||
|
||||
static Program *
|
||||
gsk_gl_renderer_create_custom_program (GskGLRenderer *self,
|
||||
GskGLShader *shader)
|
||||
{
|
||||
Program *program = g_new0 (Program, 1);
|
||||
|
||||
program_init (program);
|
||||
|
||||
g_hash_table_insert (self->programs->custom_programs, g_object_ref (shader), program);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
static GskGLRendererPrograms *
|
||||
gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
GError **error)
|
||||
@@ -2961,35 +3281,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
|
||||
g_assert (G_N_ELEMENTS (program_definitions) == GL_N_PROGRAMS);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS))
|
||||
shader_builder.debugging = TRUE;
|
||||
#endif
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->gl_context))
|
||||
{
|
||||
|
||||
gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GLES);
|
||||
shader_builder.gles = TRUE;
|
||||
}
|
||||
else if (gdk_gl_context_is_legacy (self->gl_context))
|
||||
{
|
||||
int maj, min;
|
||||
|
||||
gdk_gl_context_get_version (self->gl_context, &maj, &min);
|
||||
|
||||
if (maj == 3)
|
||||
gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GL3_LEGACY);
|
||||
else
|
||||
gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GL2_LEGACY);
|
||||
|
||||
shader_builder.legacy = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GL3);
|
||||
shader_builder.gl3 = TRUE;
|
||||
}
|
||||
init_shader_builder (self, &shader_builder);
|
||||
|
||||
programs = gsk_gl_renderer_programs_new ();
|
||||
|
||||
@@ -3000,7 +3292,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
|
||||
prog->index = i;
|
||||
prog->id = gsk_gl_shader_builder_create_program (&shader_builder,
|
||||
program_definitions[i].resource_path,
|
||||
error);
|
||||
NULL, 0, error);
|
||||
if (prog->id < 0)
|
||||
{
|
||||
g_clear_pointer (&programs, gsk_gl_renderer_programs_unref);
|
||||
@@ -3445,6 +3737,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
render_repeat_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
render_gl_shader_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
@@ -3727,6 +4023,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
|
||||
apply_source_texture_op (program, ptr);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_EXTRA_SOURCE_TEXTURE:
|
||||
apply_source_extra_texture_op (program, ptr);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_CROSS_FADE:
|
||||
g_assert (program == &self->programs->cross_fade_program);
|
||||
apply_cross_fade_op (program, ptr);
|
||||
@@ -3773,6 +4073,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
|
||||
apply_repeat_op (program, ptr);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_GL_SHADER_ARGS:
|
||||
apply_gl_shader_args_op (program, ptr);
|
||||
break;
|
||||
|
||||
case OP_DRAW:
|
||||
{
|
||||
const OpDraw *op = ptr;
|
||||
|
14
gsk/gl/gskglrendererprivate.h
Normal file
14
gsk/gl/gskglrendererprivate.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
|
||||
#define __GSK_GL_RENDERER_PRIVATE_H__
|
||||
|
||||
#include "gskglrenderer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean gsk_gl_render_try_compile_gl_shader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
|
@@ -60,7 +60,7 @@ get_current_program_state (RenderOpBuilder *builder)
|
||||
if (!builder->current_program)
|
||||
return NULL;
|
||||
|
||||
return &builder->programs->state[builder->current_program->index];
|
||||
return &builder->current_program->state;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -218,10 +218,10 @@ ops_free (RenderOpBuilder *builder)
|
||||
|
||||
void
|
||||
ops_set_program (RenderOpBuilder *builder,
|
||||
const Program *program)
|
||||
Program *program)
|
||||
{
|
||||
OpProgram *op;
|
||||
ProgramState *program_state;
|
||||
ProgramState *program_state = NULL;
|
||||
|
||||
if (builder->current_program == program)
|
||||
return;
|
||||
@@ -231,7 +231,7 @@ ops_set_program (RenderOpBuilder *builder,
|
||||
|
||||
builder->current_program = program;
|
||||
|
||||
program_state = &builder->programs->state[program->index];
|
||||
program_state = &program->state;
|
||||
|
||||
if (memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
|
||||
{
|
||||
@@ -558,6 +558,18 @@ ops_set_texture (RenderOpBuilder *builder,
|
||||
builder->current_texture = texture_id;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_extra_texture (RenderOpBuilder *builder,
|
||||
int texture_id,
|
||||
int idx)
|
||||
{
|
||||
OpExtraTexture *op;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_EXTRA_SOURCE_TEXTURE);
|
||||
op->texture_id = texture_id;
|
||||
op->idx = idx;
|
||||
}
|
||||
|
||||
int
|
||||
ops_set_render_target (RenderOpBuilder *builder,
|
||||
int render_target_id)
|
||||
@@ -621,6 +633,22 @@ ops_set_color (RenderOpBuilder *builder,
|
||||
op->rgba = color;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_gl_shader_args (RenderOpBuilder *builder,
|
||||
GskGLShader *shader,
|
||||
float width,
|
||||
float height,
|
||||
const guchar *uniform_data)
|
||||
{
|
||||
OpGLShader *op;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_GL_SHADER_ARGS);
|
||||
op->shader = shader;
|
||||
op->size[0] = width;
|
||||
op->size[1] = height;
|
||||
op->uniform_data = uniform_data;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_color_matrix (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *matrix,
|
||||
|
@@ -31,9 +31,60 @@ typedef struct
|
||||
OpsMatrixMetadata metadata;
|
||||
} MatrixStackEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskTransform *modelview;
|
||||
GskRoundedRect clip;
|
||||
graphene_matrix_t projection;
|
||||
int source_texture;
|
||||
graphene_rect_t viewport;
|
||||
float opacity;
|
||||
/* Per-program state */
|
||||
union {
|
||||
GdkRGBA color;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
float widths[4];
|
||||
GdkRGBA color;
|
||||
GskRoundedRect outline;
|
||||
} border;
|
||||
struct {
|
||||
GskRoundedRect outline;
|
||||
float dx;
|
||||
float dy;
|
||||
float spread;
|
||||
GdkRGBA color;
|
||||
} inset_shadow;
|
||||
struct {
|
||||
GskRoundedRect outline;
|
||||
float dx;
|
||||
float dy;
|
||||
float spread;
|
||||
GdkRGBA color;
|
||||
} unblurred_outset_shadow;
|
||||
struct {
|
||||
int n_color_stops;
|
||||
GskColorStop color_stops[MAX_GRADIENT_STOPS];
|
||||
float start_point[2];
|
||||
float end_point[2];
|
||||
} linear_gradient;
|
||||
struct {
|
||||
int n_color_stops;
|
||||
GskColorStop color_stops[MAX_GRADIENT_STOPS];
|
||||
float center[2];
|
||||
float start;
|
||||
float end;
|
||||
float radius[2]; /* h/v */
|
||||
} radial_gradient;
|
||||
};
|
||||
} ProgramState;
|
||||
|
||||
struct _Program
|
||||
{
|
||||
int index; /* Into the renderer's program array */
|
||||
int index; /* Into the renderer's program array -1 for custom */
|
||||
|
||||
int id;
|
||||
/* Common locations (gl_common)*/
|
||||
@@ -108,59 +159,16 @@ struct _Program
|
||||
int child_bounds_location;
|
||||
int texture_rect_location;
|
||||
} repeat;
|
||||
struct {
|
||||
int size_location;
|
||||
int args_locations[8];
|
||||
int texture_locations[4];
|
||||
GError *compile_error;
|
||||
} glshader;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskTransform *modelview;
|
||||
GskRoundedRect clip;
|
||||
graphene_matrix_t projection;
|
||||
int source_texture;
|
||||
graphene_rect_t viewport;
|
||||
float opacity;
|
||||
/* Per-program state */
|
||||
union {
|
||||
GdkRGBA color;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
float widths[4];
|
||||
GdkRGBA color;
|
||||
GskRoundedRect outline;
|
||||
} border;
|
||||
struct {
|
||||
GskRoundedRect outline;
|
||||
float dx;
|
||||
float dy;
|
||||
float spread;
|
||||
GdkRGBA color;
|
||||
} inset_shadow;
|
||||
struct {
|
||||
GskRoundedRect outline;
|
||||
float dx;
|
||||
float dy;
|
||||
float spread;
|
||||
GdkRGBA color;
|
||||
} unblurred_outset_shadow;
|
||||
struct {
|
||||
int n_color_stops;
|
||||
GskColorStop color_stops[MAX_GRADIENT_STOPS];
|
||||
float start_point[2];
|
||||
float end_point[2];
|
||||
} linear_gradient;
|
||||
struct {
|
||||
int n_color_stops;
|
||||
GskColorStop color_stops[MAX_GRADIENT_STOPS];
|
||||
float center[2];
|
||||
float start;
|
||||
float end;
|
||||
float radius[2]; /* h/v */
|
||||
} radial_gradient;
|
||||
};
|
||||
} ProgramState;
|
||||
ProgramState state;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int ref_count;
|
||||
@@ -183,13 +191,13 @@ typedef struct {
|
||||
Program unblurred_outset_shadow_program;
|
||||
};
|
||||
};
|
||||
ProgramState state[GL_N_PROGRAMS];
|
||||
GHashTable *custom_programs; /* GskGLShader -> Program* */
|
||||
} GskGLRendererPrograms;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskGLRendererPrograms *programs;
|
||||
const Program *current_program;
|
||||
Program *current_program;
|
||||
int current_render_target;
|
||||
int current_texture;
|
||||
|
||||
@@ -236,7 +244,7 @@ void ops_pop_modelview (RenderOpBuilder *builder);
|
||||
float ops_get_scale (const RenderOpBuilder *builder);
|
||||
|
||||
void ops_set_program (RenderOpBuilder *builder,
|
||||
const Program *program);
|
||||
Program *program);
|
||||
|
||||
void ops_push_clip (RenderOpBuilder *builder,
|
||||
const GskRoundedRect *clip);
|
||||
@@ -255,6 +263,9 @@ graphene_rect_t ops_set_viewport (RenderOpBuilder *builder,
|
||||
|
||||
void ops_set_texture (RenderOpBuilder *builder,
|
||||
int texture_id);
|
||||
void ops_set_extra_texture (RenderOpBuilder *builder,
|
||||
int texture_id,
|
||||
int idx);
|
||||
|
||||
int ops_set_render_target (RenderOpBuilder *builder,
|
||||
int render_target_id);
|
||||
@@ -281,6 +292,11 @@ void ops_set_inset_shadow (RenderOpBuilder *self,
|
||||
const GdkRGBA *color,
|
||||
float dx,
|
||||
float dy);
|
||||
void ops_set_gl_shader_args (RenderOpBuilder *builder,
|
||||
GskGLShader *shader,
|
||||
float width,
|
||||
float height,
|
||||
const guchar *uniform_data);
|
||||
void ops_set_unblurred_outset_shadow (RenderOpBuilder *self,
|
||||
const GskRoundedRect outline,
|
||||
float spread,
|
||||
|
@@ -39,6 +39,30 @@ gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
|
||||
self->version = version;
|
||||
}
|
||||
|
||||
static void
|
||||
prepend_line_numbers (char *code,
|
||||
GString *s)
|
||||
{
|
||||
char *p;
|
||||
int line;
|
||||
|
||||
p = code;
|
||||
line = 1;
|
||||
while (*p)
|
||||
{
|
||||
char *end = strchr (p, '\n');
|
||||
if (end)
|
||||
end = end + 1; /* Include newline */
|
||||
else
|
||||
end = p + strlen (p);
|
||||
|
||||
g_string_append_printf (s, "%3d| ", line++);
|
||||
g_string_append_len (s, p, end - p);
|
||||
|
||||
p = end;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_shader_error (int shader_id,
|
||||
GError **error)
|
||||
@@ -48,6 +72,7 @@ check_shader_error (int shader_id,
|
||||
char *buffer;
|
||||
int code_len;
|
||||
char *code;
|
||||
GString *s;
|
||||
|
||||
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
|
||||
|
||||
@@ -62,20 +87,50 @@ check_shader_error (int shader_id,
|
||||
code = g_malloc0 (code_len + 1);
|
||||
glGetShaderSource (shader_id, code_len, NULL, code);
|
||||
|
||||
s = g_string_new ("");
|
||||
prepend_line_numbers (code, s);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
|
||||
"Compilation failure in shader.\nError message: %s\n\nSource code:\n%s\n\n",
|
||||
buffer,
|
||||
code);
|
||||
s->str);
|
||||
|
||||
g_string_free (s, TRUE);
|
||||
g_free (buffer);
|
||||
g_free (code);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
print_shader_info (const char *prefix,
|
||||
int shader_id,
|
||||
const char *resource_path)
|
||||
{
|
||||
if (GSK_DEBUG_CHECK(SHADERS))
|
||||
{
|
||||
int code_len;
|
||||
char *code;
|
||||
GString *s;
|
||||
|
||||
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
|
||||
code = g_malloc0 (code_len + 1);
|
||||
glGetShaderSource (shader_id, code_len, NULL, code);
|
||||
|
||||
s = g_string_new ("");
|
||||
prepend_line_numbers (code, s);
|
||||
|
||||
g_message ("%s %d, %s:\n%s", prefix, shader_id, resource_path, s->str);
|
||||
g_string_free (s, TRUE);
|
||||
g_free (code);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
const char *resource_path,
|
||||
const char *extra_fragment_snippet,
|
||||
gsize extra_fragment_length,
|
||||
GError **error)
|
||||
{
|
||||
|
||||
@@ -135,8 +190,10 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_shader_info ("Vertex shader", vertex_id, resource_path);
|
||||
|
||||
fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
|
||||
glShaderSource (fragment_id, 8,
|
||||
glShaderSource (fragment_id, 9,
|
||||
(const char *[]) {
|
||||
version_buffer,
|
||||
self->debugging ? "#define GSK_DEBUG 1\n" : "",
|
||||
@@ -145,7 +202,8 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
self->gles ? "#define GSK_GLES 1\n" : "",
|
||||
g_bytes_get_data (self->preamble, NULL),
|
||||
g_bytes_get_data (self->fs_preamble, NULL),
|
||||
fragment_shader_start
|
||||
fragment_shader_start,
|
||||
extra_fragment_snippet ? extra_fragment_snippet : ""
|
||||
},
|
||||
(int[]) {
|
||||
-1,
|
||||
@@ -156,6 +214,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
extra_fragment_length,
|
||||
});
|
||||
glCompileShader (fragment_id);
|
||||
|
||||
@@ -165,6 +224,8 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_shader_info ("Fragment shader", vertex_id, resource_path);
|
||||
|
||||
program_id = glCreateProgram ();
|
||||
glAttachShader (program_id, vertex_id);
|
||||
glAttachShader (program_id, fragment_id);
|
||||
@@ -188,6 +249,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteProgram (program_id);
|
||||
program_id = -1;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
@@ -33,6 +33,8 @@ void gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
|
||||
|
||||
int gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
const char *resource_path,
|
||||
const char *extra_fragment_snippet,
|
||||
gsize extra_fragment_length,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -31,6 +31,8 @@ static guint op_sizes[OP_LAST] = {
|
||||
sizeof (OpDebugGroup),
|
||||
0,
|
||||
sizeof (OpBlend),
|
||||
sizeof (OpGLShader),
|
||||
sizeof (OpExtraTexture),
|
||||
};
|
||||
|
||||
void
|
||||
|
@@ -39,6 +39,8 @@ typedef enum
|
||||
OP_PUSH_DEBUG_GROUP = 25,
|
||||
OP_POP_DEBUG_GROUP = 26,
|
||||
OP_CHANGE_BLEND = 27,
|
||||
OP_CHANGE_GL_SHADER_ARGS = 28,
|
||||
OP_CHANGE_EXTRA_SOURCE_TEXTURE = 29,
|
||||
OP_LAST
|
||||
} OpKind;
|
||||
|
||||
@@ -124,6 +126,12 @@ typedef struct
|
||||
int texture_id;
|
||||
} OpTexture;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int texture_id;
|
||||
int idx;
|
||||
} OpExtraTexture;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gsize vao_offset;
|
||||
@@ -198,6 +206,13 @@ typedef struct
|
||||
float texture_rect[4];
|
||||
} OpRepeat;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float size[2];
|
||||
GskGLShader *shader;
|
||||
const guchar *uniform_data;
|
||||
} OpGLShader;
|
||||
|
||||
void op_buffer_init (OpBuffer *buffer);
|
||||
void op_buffer_destroy (OpBuffer *buffer);
|
||||
void op_buffer_clear (OpBuffer *buffer);
|
||||
|
@@ -48,6 +48,7 @@
|
||||
* @GSK_TEXT_NODE: A node containing a glyph string
|
||||
* @GSK_BLUR_NODE: A node that applies a blur
|
||||
* @GSK_DEBUG_NODE: Debug information that does not affect the rendering
|
||||
* @GSK_GL_SHADER_NODE: A node that uses OpenGL fragment shaders to render
|
||||
|
||||
* The type of a node determines what the node is rendering.
|
||||
*/
|
||||
@@ -75,7 +76,8 @@ typedef enum {
|
||||
GSK_CROSS_FADE_NODE,
|
||||
GSK_TEXT_NODE,
|
||||
GSK_BLUR_NODE,
|
||||
GSK_DEBUG_NODE
|
||||
GSK_DEBUG_NODE,
|
||||
GSK_GL_SHADER_NODE
|
||||
} GskRenderNodeType;
|
||||
|
||||
/**
|
||||
@@ -218,4 +220,32 @@ typedef enum
|
||||
GSK_TRANSFORM_CATEGORY_IDENTITY
|
||||
} GskTransformCategory;
|
||||
|
||||
/**
|
||||
* GskGLUniformType:
|
||||
* @GSK_GL_UNIFORM_TYPE_NONE: No type, used for uninitialized or unspecified values.
|
||||
* @GSK_GL_UNIFORM_TYPE_FLOAT: A float uniform
|
||||
* @GSK_GL_UNIFORM_TYPE_INT: A GLSL int / gint32 uniform
|
||||
* @GSK_GL_UNIFORM_TYPE_UINT: A GLSL uint / guint32 uniform
|
||||
* @GSK_GL_UNIFORM_TYPE_BOOL: A GLSL bool / gboolean uniform
|
||||
* @GSK_GL_UNIFORM_TYPE_VEC2: A GLSL vec2 / graphene_vec2_t uniform
|
||||
* @GSK_GL_UNIFORM_TYPE_VEC3: A GLSL vec3 / graphene_vec3_t uniform
|
||||
* @GSK_GL_UNIFORM_TYPE_VEC4: A GLSL vec4 / graphene_vec4_t uniform
|
||||
*
|
||||
* This defines the types of the uniforms that #GskGLShaders
|
||||
* declare. It defines both what the type is called in the GLSL shader
|
||||
* code, and what the corresponding C type is on the Gtk side.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GSK_GL_UNIFORM_TYPE_NONE,
|
||||
GSK_GL_UNIFORM_TYPE_FLOAT,
|
||||
GSK_GL_UNIFORM_TYPE_INT,
|
||||
GSK_GL_UNIFORM_TYPE_UINT,
|
||||
GSK_GL_UNIFORM_TYPE_BOOL,
|
||||
GSK_GL_UNIFORM_TYPE_VEC2,
|
||||
GSK_GL_UNIFORM_TYPE_VEC3,
|
||||
GSK_GL_UNIFORM_TYPE_VEC4,
|
||||
} GskGLUniformType;
|
||||
|
||||
|
||||
#endif /* __GSK_TYPES_H__ */
|
||||
|
1266
gsk/gskglshader.c
Normal file
1266
gsk/gskglshader.c
Normal file
File diff suppressed because it is too large
Load Diff
158
gsk/gskglshader.h
Normal file
158
gsk/gskglshader.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2020 Red Hat Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_GL_SHADER_H__
|
||||
#define __GSK_GL_SHADER_H__
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskenums.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_SHADER_ARGS_BUILDER (gsk_shader_args_builder_get_type ())
|
||||
|
||||
typedef struct _GskShaderArgsBuilder GskShaderArgsBuilder;
|
||||
|
||||
#define GSK_TYPE_GL_SHADER (gsk_gl_shader_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GskGLShader, gsk_gl_shader, GSK, GL_SHADER, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_gl_shader_new_from_bytes (GBytes *sourcecode);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_gl_shader_new_from_resource (const char *resource_path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_gl_shader_try_compile_for (GskGLShader *shader,
|
||||
GskRenderer *renderer,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GBytes * gsk_gl_shader_get_bytes (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_gl_shader_get_n_required_textures (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_gl_shader_get_n_uniforms (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gsk_gl_shader_get_uniform_name (GskGLShader *shader,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_gl_shader_find_uniform_by_name (GskGLShader *shader,
|
||||
const char *name);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLUniformType gsk_gl_shader_get_uniform_type (GskGLShader *shader,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_gl_shader_get_uniform_offset (GskGLShader *shader,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_gl_shader_get_args_size (GskGLShader *shader);
|
||||
|
||||
|
||||
/* Helpers for managing shader args */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GBytes * gsk_gl_shader_format_args_va (GskGLShader *shader,
|
||||
va_list uniforms);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GBytes * gsk_gl_shader_format_args (GskGLShader *shader,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
float gsk_gl_shader_get_arg_float (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gint32 gsk_gl_shader_get_arg_int (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint32 gsk_gl_shader_get_arg_uint (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_gl_shader_get_arg_bool (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_gl_shader_get_arg_vec2 (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx,
|
||||
graphene_vec2_t *out_value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_gl_shader_get_arg_vec3 (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx,
|
||||
graphene_vec3_t *out_value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_gl_shader_get_arg_vec4 (GskGLShader *shader,
|
||||
GBytes *args,
|
||||
int idx,
|
||||
graphene_vec4_t *out_value);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskShaderArgsBuilder *gsk_gl_shader_build_args (GskGLShader *shader);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_shader_args_builder_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GBytes * gsk_shader_args_builder_finish (GskShaderArgsBuilder *builder);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_free (GskShaderArgsBuilder *builder);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskShaderArgsBuilder *gsk_shader_args_builder_copy (GskShaderArgsBuilder *builder);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_float (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
float value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_int (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
gint32 value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_uint (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
guint32 value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_bool (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
gboolean value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_vec2 (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
const graphene_vec2_t *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_vec3 (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
const graphene_vec3_t *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_shader_args_builder_set_vec4 (GskShaderArgsBuilder *builder,
|
||||
int idx,
|
||||
const graphene_vec4_t *value);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_SHADER_H__ */
|
19
gsk/gskglshaderprivate.h
Normal file
19
gsk/gskglshaderprivate.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __GSK_GLSHADER_PRIVATE_H__
|
||||
#define __GSK_GLSHADER_PRIVATE_H__
|
||||
|
||||
#include <gsk/gskglshader.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
GskGLUniformType type;
|
||||
gsize offset;
|
||||
} GskGLUniform;
|
||||
|
||||
const GskGLUniform *gsk_gl_shader_get_uniforms (GskGLShader *shader,
|
||||
int *n_uniforms);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GLSHADER_PRIVATE_H__ */
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <gsk/gskroundedrect.h>
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskglshader.h>
|
||||
#include <gtk/css/gtkcss.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -122,6 +123,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
|
||||
#define GSK_TYPE_CROSS_FADE_NODE (gsk_cross_fade_node_get_type())
|
||||
#define GSK_TYPE_TEXT_NODE (gsk_text_node_get_type())
|
||||
#define GSK_TYPE_BLUR_NODE (gsk_blur_node_get_type())
|
||||
#define GSK_TYPE_GL_SHADER_NODE (gsk_gl_shader_node_get_type())
|
||||
|
||||
typedef struct _GskDebugNode GskDebugNode;
|
||||
typedef struct _GskColorNode GskColorNode;
|
||||
@@ -146,6 +148,7 @@ typedef struct _GskBlendNode GskBlendNode;
|
||||
typedef struct _GskCrossFadeNode GskCrossFadeNode;
|
||||
typedef struct _GskTextNode GskTextNode;
|
||||
typedef struct _GskBlurNode GskBlurNode;
|
||||
typedef struct _GskGLShaderNode GskGLShaderNode;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_debug_node_get_type (void) G_GNUC_CONST;
|
||||
@@ -451,6 +454,24 @@ GskRenderNode * gsk_blur_node_get_child (GskRenderNode
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
float gsk_blur_node_get_radius (GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_gl_shader_node_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_gl_shader_node_new (GskGLShader *shader,
|
||||
const graphene_rect_t *bounds,
|
||||
GBytes *args,
|
||||
GskRenderNode **children,
|
||||
int n_children);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gsk_gl_shader_node_get_n_children (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_gl_shader_node_get_child (GskRenderNode *node,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GBytes * gsk_gl_shader_node_get_args (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_gl_shader_node_get_shader (GskRenderNode *node);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_H__ */
|
||||
|
@@ -4470,6 +4470,208 @@ gsk_debug_node_get_message (GskRenderNode *node)
|
||||
return self->message;
|
||||
}
|
||||
|
||||
/*** GSK_GL_SHADER_NODE ***/
|
||||
|
||||
struct _GskGLShaderNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
GskGLShader *shader;
|
||||
GBytes *args;
|
||||
GskRenderNode **children;
|
||||
guint n_children;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_gl_shader_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_GL_SHADER_NODE));
|
||||
|
||||
for (guint i = 0; i < self->n_children; i++)
|
||||
gsk_render_node_unref (self->children[i]);
|
||||
g_free (self->children);
|
||||
|
||||
g_bytes_unref (self->args);
|
||||
|
||||
g_object_unref (self->shader);
|
||||
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_shader_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
cairo_set_source_rgb (cr, 255 / 255., 105 / 255., 180 / 255.);
|
||||
gsk_cairo_rectangle (cr, &node->bounds);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_shader_node_diff (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GskGLShaderNode *self1 = (GskGLShaderNode *) node1;
|
||||
GskGLShaderNode *self2 = (GskGLShaderNode *) node2;
|
||||
|
||||
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
|
||||
self1->shader == self2->shader &&
|
||||
g_bytes_compare (self1->args, self2->args) == 0 &&
|
||||
self1->n_children == self2->n_children)
|
||||
{
|
||||
for (guint i = 0; i < self1->n_children; i++)
|
||||
{
|
||||
if (self1->children[i] != self2->children[i])
|
||||
{
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_shader_node_new:
|
||||
* @shader: the #GskGLShader
|
||||
* @bounds: the rectangle to render the shader into
|
||||
* @args: Arguments for the uniforms
|
||||
* @children: List of child nodes, these will be rendered to textures and used as input.
|
||||
* @n_children: Length of @children (currenly the GL backend only supports max 4 children)
|
||||
*
|
||||
* Creates a #GskRenderNode that will render the given @shader into the area
|
||||
* given by @bounds. The @args is a block of data to use for uniform
|
||||
* input, as per types and offsets defined by the @shader. Normally this is
|
||||
* generated by gsk_gl_shader_format_args() or #GskGLShaderArgBuilder.
|
||||
*
|
||||
* See #GskGLShader for details about how the shader should be written.
|
||||
*
|
||||
* All the children will be rendered into textures (if they aren't already
|
||||
* #GskTextureNodes, which will be used directly). These textures will be
|
||||
* sent as input to the shader.
|
||||
*
|
||||
* If the renderer doesn't support GL shaders, or if there is any problem when
|
||||
* compiling the shader, then the node will draw pink. You should use
|
||||
* gsk_gl_shader_try_compile_for() to ensure the @shader will work for the renderer
|
||||
* before using it.
|
||||
*
|
||||
* Returns: (transfer full) (type GskGLShaderNode): A new #GskRenderNode
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_gl_shader_node_new (GskGLShader *shader,
|
||||
const graphene_rect_t *bounds,
|
||||
GBytes *args,
|
||||
GskRenderNode **children,
|
||||
int n_children)
|
||||
{
|
||||
GskGLShaderNode *self;
|
||||
GskRenderNode *node;
|
||||
int uniforms_size;
|
||||
|
||||
g_return_val_if_fail (bounds != NULL, NULL);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_GL_SHADER_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, bounds);
|
||||
self->shader = g_object_ref (shader);
|
||||
|
||||
uniforms_size = gsk_gl_shader_get_args_size (shader);
|
||||
g_assert (g_bytes_get_size (args) == uniforms_size);
|
||||
|
||||
self->args = g_bytes_ref (args);
|
||||
|
||||
self->n_children = n_children;
|
||||
if (n_children > 0)
|
||||
{
|
||||
self->children = g_malloc_n (n_children, sizeof (GskRenderNode *));
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
self->children[i] = gsk_render_node_ref (children[i]);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_shader_node_get_n_children:
|
||||
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
|
||||
*
|
||||
* Returns the number of (non-fallback) children
|
||||
*
|
||||
* Returns: The number of children
|
||||
*/
|
||||
guint
|
||||
gsk_gl_shader_node_get_n_children (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), 0);
|
||||
|
||||
return self->n_children;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_shader_node_get_child:
|
||||
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
|
||||
* @idx: the position of the child to get
|
||||
*
|
||||
* Gets one of the (non-fallback) children.
|
||||
*
|
||||
* Returns: (transfer none): the @idx'th child of @node
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_gl_shader_node_get_child (GskRenderNode *node,
|
||||
int idx)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
|
||||
g_return_val_if_fail (idx < self->n_children, NULL);
|
||||
|
||||
return self->children[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_shader_node_get_shader:
|
||||
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
|
||||
*
|
||||
* Gets shader code for the node.
|
||||
*
|
||||
* Returns: (transfer none): the #GskGLShader shader
|
||||
*/
|
||||
GskGLShader *
|
||||
gsk_gl_shader_node_get_shader (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), 0);
|
||||
|
||||
return self->shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_shader_node_get_args:
|
||||
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
|
||||
*
|
||||
* Gets args for the node.
|
||||
*
|
||||
* Returns: (transfer none): A #GBytes with the uniform arguments
|
||||
*/
|
||||
GBytes *
|
||||
gsk_gl_shader_node_get_args (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
|
||||
|
||||
return self->args;
|
||||
}
|
||||
|
||||
GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES];
|
||||
|
||||
#ifndef I_
|
||||
@@ -4506,6 +4708,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_text_node, GSK_TEXT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_blur_node, GSK_BLUR_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE)
|
||||
|
||||
static void
|
||||
@@ -4863,6 +5066,22 @@ gsk_render_node_init_types_once (void)
|
||||
gsk_render_node_types[GSK_BLUR_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
GSK_GL_SHADER_NODE,
|
||||
sizeof (GskGLShaderNode),
|
||||
NULL,
|
||||
gsk_gl_shader_node_finalize,
|
||||
gsk_gl_shader_node_draw,
|
||||
NULL,
|
||||
gsk_gl_shader_node_diff,
|
||||
};
|
||||
|
||||
GType node_type = gsk_render_node_type_register_static (I_("GskGLShaderNode"), &node_info);
|
||||
gsk_render_node_types[GSK_GL_SHADER_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
|
@@ -824,9 +824,9 @@ clear_node (gpointer inout_node)
|
||||
static GskRenderNode *
|
||||
parse_container_node (GtkCssParser *parser)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
GPtrArray *nodes;
|
||||
const GtkCssToken *token;
|
||||
GskRenderNode *node;
|
||||
|
||||
nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
|
||||
|
||||
@@ -1089,6 +1089,233 @@ parse_inset_shadow_node (GtkCssParser *parser)
|
||||
return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
|
||||
}
|
||||
|
||||
typedef union {
|
||||
gint32 i;
|
||||
double v[4];
|
||||
} UniformValue;
|
||||
|
||||
typedef struct {
|
||||
GskGLShader *shader;
|
||||
GArray *uniform_values;
|
||||
} ShaderInfo;
|
||||
|
||||
static void
|
||||
clear_shader_info (gpointer data)
|
||||
{
|
||||
ShaderInfo *info = data;
|
||||
g_array_set_size (info->uniform_values, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_shader (GtkCssParser *parser,
|
||||
gpointer out_shader_info)
|
||||
{
|
||||
ShaderInfo *shader_info = out_shader_info;
|
||||
char *sourcecode = NULL;
|
||||
GBytes *bytes;
|
||||
GskGLShader *shader;
|
||||
|
||||
if (!parse_string (parser, &sourcecode))
|
||||
return FALSE;
|
||||
|
||||
bytes = g_bytes_new_take (sourcecode, strlen (sourcecode));
|
||||
shader = gsk_gl_shader_new_from_bytes (bytes);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
shader_info->shader = shader;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_uniform_value (GtkCssParser *parser,
|
||||
GskGLUniformType uniform_type,
|
||||
UniformValue *value)
|
||||
{
|
||||
switch (uniform_type)
|
||||
{
|
||||
case GSK_GL_UNIFORM_TYPE_FLOAT:
|
||||
if (!gtk_css_parser_consume_number (parser, &value->v[0]))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_INT:
|
||||
if (!gtk_css_parser_consume_integer (parser, &value->i))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_UINT:
|
||||
if (!gtk_css_parser_consume_integer (parser, &value->i) ||
|
||||
value->i < 0)
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_BOOL:
|
||||
if (!gtk_css_parser_consume_integer (parser, &value->i) ||
|
||||
(value->i != 0 && value->i != 1))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC2:
|
||||
if (!gtk_css_parser_consume_number (parser, &value->v[0]) ||
|
||||
!gtk_css_parser_consume_number (parser, &value->v[1]))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC3:
|
||||
if (!gtk_css_parser_consume_number (parser, &value->v[0]) ||
|
||||
!gtk_css_parser_consume_number (parser, &value->v[1]) ||
|
||||
!gtk_css_parser_consume_number (parser, &value->v[2]))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC4:
|
||||
if (!gtk_css_parser_consume_number (parser, &value->v[0]) ||
|
||||
!gtk_css_parser_consume_number (parser, &value->v[1]) ||
|
||||
!gtk_css_parser_consume_number (parser, &value->v[2]) ||
|
||||
!gtk_css_parser_consume_number (parser, &value->v[3]))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_shader_args (GtkCssParser *parser, gpointer data)
|
||||
{
|
||||
ShaderInfo *shader_info = data;
|
||||
int n_uniforms = gsk_gl_shader_get_n_uniforms (shader_info->shader);
|
||||
int i;
|
||||
|
||||
g_array_set_size (shader_info->uniform_values, n_uniforms);
|
||||
|
||||
for (i = 0; i < n_uniforms; i++)
|
||||
{
|
||||
GskGLUniformType uniform_type = gsk_gl_shader_get_uniform_type (shader_info->shader, i);
|
||||
UniformValue *uniform_value = &g_array_index (shader_info->uniform_values, UniformValue, i);
|
||||
|
||||
if (!parse_uniform_value (parser, uniform_type, uniform_value))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_glshader_node (GtkCssParser *parser)
|
||||
{
|
||||
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
|
||||
GskRenderNode *child[4] = { NULL, };
|
||||
ShaderInfo shader_info = {
|
||||
NULL,
|
||||
g_array_new (FALSE, FALSE, sizeof (UniformValue))
|
||||
};
|
||||
const Declaration declarations[] = {
|
||||
{ "bounds", parse_rect, NULL, &bounds },
|
||||
{ "sourcecode", parse_shader, NULL, &shader_info },
|
||||
{ "uniform-data", parse_shader_args, clear_shader_info, &shader_info },
|
||||
{ "child1", parse_node, clear_node, &child[0] },
|
||||
{ "child2", parse_node, clear_node, &child[1] },
|
||||
{ "child3", parse_node, clear_node, &child[2] },
|
||||
{ "child4", parse_node, clear_node, &child[3] },
|
||||
};
|
||||
GskGLShader *shader;
|
||||
GskRenderNode *node;
|
||||
GskShaderArgsBuilder *builder;
|
||||
GBytes *args = NULL;
|
||||
int len, i;
|
||||
|
||||
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
|
||||
|
||||
for (len = 0; len < 4; len++)
|
||||
{
|
||||
if (child[len] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
shader = shader_info.shader;
|
||||
|
||||
builder = gsk_gl_shader_build_args (shader);
|
||||
for (i = 0; i < shader_info.uniform_values->len; i++)
|
||||
{
|
||||
GskGLUniformType uniform_type = gsk_gl_shader_get_uniform_type (shader, i);
|
||||
UniformValue *value = &g_array_index (shader_info.uniform_values, UniformValue, i);
|
||||
|
||||
switch (uniform_type)
|
||||
{
|
||||
case GSK_GL_UNIFORM_TYPE_FLOAT:
|
||||
gsk_shader_args_builder_set_float (builder, i, value->v[0]);
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_INT:
|
||||
gsk_shader_args_builder_set_int (builder, i, value->i);
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_UINT:
|
||||
gsk_shader_args_builder_set_uint (builder, i, value->i);
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_BOOL:
|
||||
gsk_shader_args_builder_set_bool (builder, i, value->i);
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC2:
|
||||
{
|
||||
graphene_vec2_t v;
|
||||
graphene_vec2_init (&v, value->v[0], value->v[1]);
|
||||
gsk_shader_args_builder_set_vec2 (builder, i, &v);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC3:
|
||||
{
|
||||
graphene_vec3_t v;
|
||||
graphene_vec3_init (&v, value->v[0], value->v[1], value->v[2]);
|
||||
gsk_shader_args_builder_set_vec3 (builder, i, &v);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC4:
|
||||
{
|
||||
graphene_vec4_t v;
|
||||
graphene_vec4_init (&v, value->v[0], value->v[1], value->v[2], value->v[3]);
|
||||
gsk_shader_args_builder_set_vec4 (builder, i, &v);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
args = gsk_shader_args_builder_finish (builder);
|
||||
gsk_shader_args_builder_free (builder);
|
||||
|
||||
node = gsk_gl_shader_node_new (shader, &bounds, args,
|
||||
child, len);
|
||||
|
||||
g_array_unref (shader_info.uniform_values);
|
||||
g_bytes_unref (args);
|
||||
g_object_unref (shader);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (child[i])
|
||||
gsk_render_node_unref (child[i]);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_border_node (GtkCssParser *parser)
|
||||
{
|
||||
@@ -1603,6 +1830,7 @@ parse_node (GtkCssParser *parser,
|
||||
{ "text", parse_text_node },
|
||||
{ "texture", parse_texture_node },
|
||||
{ "transform", parse_transform_node },
|
||||
{ "glshader", parse_glshader_node },
|
||||
};
|
||||
GskRenderNode **node_p = out_node;
|
||||
guint i;
|
||||
@@ -1837,6 +2065,51 @@ append_point (GString *str,
|
||||
string_append_double (str, p->y);
|
||||
}
|
||||
|
||||
static void
|
||||
append_string (GString *str,
|
||||
const char *string)
|
||||
{
|
||||
gsize len;
|
||||
|
||||
g_return_if_fail (str != NULL);
|
||||
g_return_if_fail (string != NULL);
|
||||
|
||||
g_string_append_c (str, '"');
|
||||
|
||||
do {
|
||||
len = strcspn (string, "\\\"\n\r\f");
|
||||
g_string_append_len (str, string, len);
|
||||
string += len;
|
||||
switch (*string)
|
||||
{
|
||||
case '\0':
|
||||
goto out;
|
||||
case '\n':
|
||||
g_string_append (str, "\\A ");
|
||||
break;
|
||||
case '\r':
|
||||
g_string_append (str, "\\D ");
|
||||
break;
|
||||
case '\f':
|
||||
g_string_append (str, "\\C ");
|
||||
break;
|
||||
case '\"':
|
||||
g_string_append (str, "\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
g_string_append (str, "\\\\");
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
string++;
|
||||
} while (*string);
|
||||
|
||||
out:
|
||||
g_string_append_c (str, '"');
|
||||
}
|
||||
|
||||
static void
|
||||
append_vec4 (GString *str,
|
||||
const graphene_vec4_t *v)
|
||||
@@ -1914,6 +2187,18 @@ append_point_param (Printer *p,
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
append_string_param (Printer *p,
|
||||
const char *param_name,
|
||||
const char *value)
|
||||
{
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "%s: ", param_name);
|
||||
append_string (p->str, value);
|
||||
g_string_append_c (p->str, ';');
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
append_vec4_param (Printer *p,
|
||||
const char *param_name,
|
||||
@@ -2441,6 +2726,124 @@ render_node_print (Printer *p,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
{
|
||||
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
|
||||
GBytes *args = gsk_gl_shader_node_get_args (node);
|
||||
|
||||
start_node (p, "glshader");
|
||||
|
||||
append_rect_param (p, "bounds", &node->bounds);
|
||||
|
||||
GBytes *bytes = gsk_gl_shader_get_bytes (shader);
|
||||
/* Ensure we are zero-terminated */
|
||||
char *sourcecode = g_strndup (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
|
||||
append_string_param (p, "sourcecode", sourcecode);
|
||||
g_free (sourcecode);
|
||||
|
||||
if (gsk_gl_shader_get_n_uniforms (shader) > 0)
|
||||
{
|
||||
GString *data = g_string_new ("");
|
||||
|
||||
for (guint i = 0; i < gsk_gl_shader_get_n_uniforms (shader); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
g_string_append (data, ", ");
|
||||
|
||||
switch (gsk_gl_shader_get_uniform_type (shader, i))
|
||||
{
|
||||
case GSK_GL_UNIFORM_TYPE_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_FLOAT:
|
||||
{
|
||||
float value = gsk_gl_shader_get_arg_float (shader, args, i);
|
||||
string_append_double (data, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_INT:
|
||||
{
|
||||
gint32 value = gsk_gl_shader_get_arg_int (shader, args, i);
|
||||
g_string_append_printf (data, "%d", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_UINT:
|
||||
{
|
||||
guint32 value = gsk_gl_shader_get_arg_uint (shader, args, i);
|
||||
g_string_append_printf (data, "%u", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_BOOL:
|
||||
{
|
||||
gboolean value = gsk_gl_shader_get_arg_bool (shader, args, i);
|
||||
g_string_append_printf (data, "%d", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC2:
|
||||
{
|
||||
graphene_vec2_t value;
|
||||
gsk_gl_shader_get_arg_vec2 (shader, args, i,
|
||||
&value);
|
||||
string_append_double (data, graphene_vec2_get_x (&value));
|
||||
g_string_append (data, " ");
|
||||
string_append_double (data, graphene_vec2_get_y (&value));
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC3:
|
||||
{
|
||||
graphene_vec3_t value;
|
||||
gsk_gl_shader_get_arg_vec3 (shader, args, i,
|
||||
&value);
|
||||
string_append_double (data, graphene_vec3_get_x (&value));
|
||||
g_string_append (data, " ");
|
||||
string_append_double (data, graphene_vec3_get_y (&value));
|
||||
g_string_append (data, " ");
|
||||
string_append_double (data, graphene_vec3_get_z (&value));
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC4:
|
||||
{
|
||||
graphene_vec4_t value;
|
||||
gsk_gl_shader_get_arg_vec4 (shader, args, i,
|
||||
&value);
|
||||
string_append_double (data, graphene_vec4_get_x (&value));
|
||||
g_string_append (data, " ");
|
||||
string_append_double (data, graphene_vec4_get_y (&value));
|
||||
g_string_append (data, " ");
|
||||
string_append_double (data, graphene_vec4_get_z (&value));
|
||||
g_string_append (data, " ");
|
||||
string_append_double (data, graphene_vec4_get_w (&value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "uniform-data: %s;\n", data->str);
|
||||
g_string_free (data, TRUE);
|
||||
}
|
||||
|
||||
for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i ++)
|
||||
{
|
||||
GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
|
||||
char *name;
|
||||
|
||||
name = g_strdup_printf ("child%d", i + 1);
|
||||
append_node_param (p, name, child);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_REPEAT_NODE:
|
||||
{
|
||||
GskRenderNode *child = gsk_repeat_node_get_child (node);
|
||||
|
@@ -13,7 +13,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass;
|
||||
* We don't add an "n-types" value to avoid having to handle
|
||||
* it in every single switch.
|
||||
*/
|
||||
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_DEBUG_NODE + 1)
|
||||
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_GL_SHADER_NODE + 1)
|
||||
|
||||
extern GType gsk_render_node_types[];
|
||||
|
||||
|
@@ -16,11 +16,13 @@ gsk_private_gl_shaders = [
|
||||
'resources/glsl/cross_fade.glsl',
|
||||
'resources/glsl/blend.glsl',
|
||||
'resources/glsl/repeat.glsl',
|
||||
'resources/glsl/custom.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
'gskdiff.c',
|
||||
'gskcairorenderer.c',
|
||||
'gskglshader.c',
|
||||
'gskrenderer.c',
|
||||
'gskrendernode.c',
|
||||
'gskrendernodeimpl.c',
|
||||
@@ -52,6 +54,7 @@ gsk_private_sources = files([
|
||||
gsk_public_headers = files([
|
||||
'gskcairorenderer.h',
|
||||
'gskenums.h',
|
||||
'gskglshader.h',
|
||||
'gskrenderer.h',
|
||||
'gskrendernode.h',
|
||||
'gskroundedrect.h',
|
||||
|
@@ -267,8 +267,8 @@ luminosity (vec4 Cs, vec4 Cb)
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 bottom_color = Texture(u_source, vUv);
|
||||
vec4 top_color = Texture(u_source2, vUv);
|
||||
vec4 bottom_color = GskTexture(u_source, vUv);
|
||||
vec4 top_color = GskTexture(u_source2, vUv);
|
||||
|
||||
vec4 result;
|
||||
if (u_mode == 0)
|
||||
@@ -306,5 +306,5 @@ void main() {
|
||||
else
|
||||
discard;
|
||||
|
||||
setOutputColor(result * u_alpha);
|
||||
gskSetOutputColor(result * u_alpha);
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ void main() {
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
void main() {
|
||||
vec4 diffuse = Texture(u_source, vUv);
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
setOutputColor(diffuse * u_alpha);
|
||||
gskSetOutputColor(diffuse * u_alpha);
|
||||
}
|
||||
|
@@ -39,14 +39,14 @@ void main() {
|
||||
vec3 incrementalGaussian = initial_gaussian;
|
||||
|
||||
float coefficientSum = 0.0;
|
||||
vec4 sum = Texture(u_source, vUv) * incrementalGaussian.x;
|
||||
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 += Texture(u_source, vUv - p) * incrementalGaussian.x;
|
||||
sum += Texture(u_source, vUv + p) * incrementalGaussian.x;
|
||||
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;
|
||||
@@ -54,5 +54,5 @@ void main() {
|
||||
p += pixel_step;
|
||||
}
|
||||
|
||||
setOutputColor(sum / coefficientSum);
|
||||
gskSetOutputColor(sum / coefficientSum);
|
||||
}
|
||||
|
@@ -4,37 +4,37 @@ uniform vec4 u_widths;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
_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 = premultiply(u_color) * u_alpha;
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
|
||||
RoundedRect outside = create_rect(u_outline_rect);
|
||||
RoundedRect inside = rounded_rect_shrink (outside, u_widths);
|
||||
GskRoundedRect outside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
|
||||
|
||||
rounded_rect_transform(outside, u_modelview);
|
||||
rounded_rect_transform(inside, u_modelview);
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
rounded_rect_encode(outside, transformed_outside_outline);
|
||||
rounded_rect_encode(inside, transformed_inside_outline);
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = get_frag_coord();
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), frag) -
|
||||
rounded_rect_coverage(decode_rect(transformed_inside_outline), frag),
|
||||
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);
|
||||
|
||||
setOutputColor(final_color * alpha);
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
|
@@ -6,13 +6,13 @@ _OUT_ vec4 final_color;
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
final_color = premultiply(u_color) * u_alpha;
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
|
||||
void main() {
|
||||
setOutputColor(final_color);
|
||||
gskSetOutputColor(final_color);
|
||||
}
|
||||
|
||||
|
@@ -10,7 +10,7 @@ uniform mat4 u_color_matrix;
|
||||
uniform vec4 u_color_offset;
|
||||
|
||||
void main() {
|
||||
vec4 color = Texture(u_source, vUv);
|
||||
vec4 color = GskTexture(u_source, vUv);
|
||||
|
||||
// Un-premultilpy
|
||||
if (color.a != 0.0)
|
||||
@@ -21,5 +21,5 @@ void main() {
|
||||
|
||||
color.rgb *= color.a;
|
||||
|
||||
setOutputColor(color * u_alpha);
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ void main() {
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
|
||||
final_color = premultiply(u_color) * u_alpha;
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
@@ -16,7 +16,7 @@ void main() {
|
||||
_IN_ vec4 final_color;
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = Texture(u_source, vUv);
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
setOutputColor(final_color * diffuse.a);
|
||||
gskSetOutputColor(final_color * diffuse.a);
|
||||
}
|
||||
|
@@ -10,11 +10,11 @@ uniform float u_progress;
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
void main() {
|
||||
vec4 source1 = Texture(u_source, vUv); // start child
|
||||
vec4 source2 = Texture(u_source2, vUv); // end child
|
||||
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);
|
||||
setOutputColor(color);
|
||||
gskSetOutputColor(color);
|
||||
}
|
||||
|
21
gsk/resources/glsl/custom.glsl
Normal file
21
gsk/resources/glsl/custom.glsl
Normal file
@@ -0,0 +1,21 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// 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(gsk_premultiply(fragColor));
|
||||
}
|
@@ -5,8 +5,8 @@ uniform vec2 u_offset;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
_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);
|
||||
@@ -15,29 +15,29 @@ void main() {
|
||||
final_color.rgb *= final_color.a;
|
||||
final_color *= u_alpha;
|
||||
|
||||
RoundedRect outside = create_rect(u_outline_rect);
|
||||
RoundedRect inside = rounded_rect_shrink(outside, vec4(u_spread));
|
||||
GskRoundedRect outside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread));
|
||||
|
||||
rounded_rect_offset(inside, u_offset);
|
||||
gsk_rounded_rect_offset(inside, u_offset);
|
||||
|
||||
rounded_rect_transform(outside, u_modelview);
|
||||
rounded_rect_transform(inside, u_modelview);
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
rounded_rect_encode(outside, transformed_outside_outline);
|
||||
rounded_rect_encode(inside, transformed_inside_outline);
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = get_frag_coord();
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), frag) -
|
||||
rounded_rect_coverage(decode_rect(transformed_inside_outline), frag),
|
||||
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);
|
||||
|
||||
setOutputColor(final_color * alpha);
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
|
@@ -25,10 +25,10 @@ void main() {
|
||||
|
||||
for (int i = 0; i < u_num_color_stops; i ++) {
|
||||
color_offsets[i] = u_color_stops[(i * 5) + 0];
|
||||
color_stops[i] = premultiply(vec4(u_color_stops[(i * 5) + 1],
|
||||
u_color_stops[(i * 5) + 2],
|
||||
u_color_stops[(i * 5) + 3],
|
||||
u_color_stops[(i * 5) + 4]));
|
||||
color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1],
|
||||
u_color_stops[(i * 5) + 2],
|
||||
u_color_stops[(i * 5) + 3],
|
||||
u_color_stops[(i * 5) + 4]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ _IN_ float color_offsets[8];
|
||||
|
||||
void main() {
|
||||
// Position relative to startPoint
|
||||
vec2 pos = get_frag_coord() - startPoint;
|
||||
vec2 pos = gsk_get_frag_coord() - startPoint;
|
||||
|
||||
// Current pixel, projected onto the line between the start point and the end point
|
||||
// The projection will be relative to the start point!
|
||||
@@ -66,5 +66,5 @@ void main() {
|
||||
}
|
||||
}
|
||||
|
||||
setOutputColor(color * u_alpha);
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
}
|
||||
|
@@ -3,31 +3,31 @@ uniform vec4 u_color;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outline;
|
||||
_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 = premultiply(u_color) * u_alpha;
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
|
||||
RoundedRect outline = create_rect(u_outline_rect);
|
||||
rounded_rect_transform(outline, u_modelview);
|
||||
rounded_rect_encode(outline, transformed_outline);
|
||||
GskRoundedRect outline = gsk_create_rect(u_outline_rect);
|
||||
gsk_rounded_rect_transform(outline, u_modelview);
|
||||
gsk_rounded_rect_encode(outline, transformed_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = get_frag_coord();
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = Texture(u_source, vUv).a;
|
||||
alpha *= (1.0 - clamp(rounded_rect_coverage(decode_rect(transformed_outline), frag), 0.0, 1.0));
|
||||
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;
|
||||
|
||||
setOutputColor(color);
|
||||
gskSetOutputColor(color);
|
||||
}
|
||||
|
@@ -16,17 +16,17 @@ _IN_ vec2 vUv;
|
||||
|
||||
|
||||
|
||||
RoundedRect decode_rect(_ROUNDED_RECT_UNIFORM_ r)
|
||||
GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r)
|
||||
{
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
return RoundedRect(r[0], r[1], r[2]);
|
||||
return GskRoundedRect(r[0], r[1], r[2]);
|
||||
#else
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
float
|
||||
ellipsis_dist (vec2 p, vec2 radius)
|
||||
gsk_ellipsis_dist (vec2 p, vec2 radius)
|
||||
{
|
||||
if (radius == vec2(0, 0))
|
||||
return 0.0;
|
||||
@@ -38,14 +38,14 @@ ellipsis_dist (vec2 p, vec2 radius)
|
||||
}
|
||||
|
||||
float
|
||||
ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
|
||||
gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
|
||||
{
|
||||
float d = ellipsis_dist (point - center, radius);
|
||||
float d = gsk_ellipsis_dist (point - center, radius);
|
||||
return clamp (0.5 - d, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float
|
||||
rounded_rect_coverage (RoundedRect r, vec2 p)
|
||||
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)
|
||||
@@ -61,10 +61,10 @@ rounded_rect_coverage (RoundedRect r, vec2 p)
|
||||
vec2 ref_br = r.corner_points2.xy;
|
||||
vec2 ref_bl = r.corner_points2.zw;
|
||||
|
||||
float d_tl = ellipsis_coverage(p, ref_tl, rad_tl);
|
||||
float d_tr = ellipsis_coverage(p, ref_tr, rad_tr);
|
||||
float d_br = ellipsis_coverage(p, ref_br, rad_br);
|
||||
float d_bl = ellipsis_coverage(p, ref_bl, rad_bl);
|
||||
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);
|
||||
|
||||
@@ -76,7 +76,7 @@ rounded_rect_coverage (RoundedRect r, vec2 p)
|
||||
return 1.0 - dot(vec4(is_out), corner_coverages);
|
||||
}
|
||||
|
||||
vec4 Texture(sampler2D sampler, vec2 texCoords) {
|
||||
vec4 GskTexture(sampler2D sampler, vec2 texCoords) {
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
return texture2D(sampler, texCoords);
|
||||
#else
|
||||
@@ -88,7 +88,7 @@ vec4 Texture(sampler2D sampler, vec2 texCoords) {
|
||||
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||
#endif
|
||||
|
||||
vec2 get_frag_coord() {
|
||||
vec2 gsk_get_frag_coord() {
|
||||
vec2 fc = gl_FragCoord.xy;
|
||||
|
||||
#ifdef GSK_GL3
|
||||
@@ -101,15 +101,15 @@ vec2 get_frag_coord() {
|
||||
return fc;
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 color) {
|
||||
vec2 f = get_frag_coord();
|
||||
void gskSetOutputColor(vec4 color) {
|
||||
vec2 f = gsk_get_frag_coord();
|
||||
|
||||
// We do *NOT* transform the clip rect here since we already
|
||||
// need to do that on the CPU.
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
gl_FragColor = color * rounded_rect_coverage(create_rect(u_clip_rect), f);
|
||||
gl_FragColor = color * gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), f);
|
||||
#else
|
||||
outputColor = color * rounded_rect_coverage(create_rect(u_clip_rect), f);
|
||||
outputColor = color * gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), f);
|
||||
#endif
|
||||
/*outputColor = color;*/
|
||||
}
|
||||
|
@@ -5,15 +5,15 @@ precision highp float;
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
#define _OUT_ varying
|
||||
#define _IN_ varying
|
||||
#define _ROUNDED_RECT_UNIFORM_ vec4[3]
|
||||
#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3]
|
||||
#else
|
||||
#define _OUT_ out
|
||||
#define _IN_ in
|
||||
#define _ROUNDED_RECT_UNIFORM_ RoundedRect
|
||||
#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect
|
||||
#endif
|
||||
|
||||
|
||||
struct RoundedRect
|
||||
struct GskRoundedRect
|
||||
{
|
||||
vec4 bounds;
|
||||
// Look, arrays can't be in structs if you want to return the struct
|
||||
@@ -22,9 +22,9 @@ struct RoundedRect
|
||||
vec4 corner_points2; // xy = bottom right, zw = bottom left
|
||||
};
|
||||
|
||||
// Transform from a GskRoundedRect to a RoundedRect as we need it.
|
||||
RoundedRect
|
||||
create_rect(vec4[3] data)
|
||||
// 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);
|
||||
|
||||
@@ -33,9 +33,9 @@ create_rect(vec4[3] data)
|
||||
vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)),
|
||||
bounds.xw + vec2(data[2].zw * vec2(1, -1)));
|
||||
|
||||
return RoundedRect(bounds, corner_points1, corner_points2);
|
||||
return GskRoundedRect(bounds, corner_points1, corner_points2);
|
||||
}
|
||||
|
||||
vec4 premultiply(vec4 c) {
|
||||
vec4 gsk_premultiply(vec4 c) {
|
||||
return vec4(c.rgb * c.a, c.a);
|
||||
}
|
||||
|
@@ -13,8 +13,8 @@ _OUT_ vec2 vUv;
|
||||
#endif
|
||||
|
||||
// amount is: top, right, bottom, left
|
||||
RoundedRect
|
||||
rounded_rect_shrink (RoundedRect r, vec4 amount)
|
||||
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;
|
||||
@@ -25,11 +25,11 @@ rounded_rect_shrink (RoundedRect r, vec4 amount)
|
||||
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 RoundedRect (new_bounds, new_corner_points1, new_corner_points2);
|
||||
return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2);
|
||||
}
|
||||
|
||||
void
|
||||
rounded_rect_offset(inout RoundedRect r, vec2 offset)
|
||||
gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset)
|
||||
{
|
||||
r.bounds.xy += offset;
|
||||
r.bounds.zw += offset;
|
||||
@@ -39,7 +39,7 @@ rounded_rect_offset(inout RoundedRect r, vec2 offset)
|
||||
r.corner_points2.zw += offset;
|
||||
}
|
||||
|
||||
void rounded_rect_transform(inout RoundedRect r, mat4 mat)
|
||||
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;
|
||||
@@ -53,9 +53,9 @@ void rounded_rect_transform(inout RoundedRect r, mat4 mat)
|
||||
|
||||
#if defined(GSK_LEGACY)
|
||||
// Can't have out or inout array parameters...
|
||||
#define rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2;
|
||||
#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2;
|
||||
#else
|
||||
void rounded_rect_encode(RoundedRect r, out _ROUNDED_RECT_UNIFORM_ out_r)
|
||||
void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r)
|
||||
{
|
||||
#if defined(GSK_GLES)
|
||||
out_r[0] = r.bounds;
|
||||
|
@@ -21,10 +21,10 @@ void main() {
|
||||
|
||||
for (int i = 0; i < u_num_color_stops; i ++) {
|
||||
color_offsets[i] = u_color_stops[(i * 5) + 0];
|
||||
color_stops[i] = premultiply(vec4(u_color_stops[(i * 5) + 1],
|
||||
u_color_stops[(i * 5) + 2],
|
||||
u_color_stops[(i * 5) + 3],
|
||||
u_color_stops[(i * 5) + 4]));
|
||||
color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1],
|
||||
u_color_stops[(i * 5) + 2],
|
||||
u_color_stops[(i * 5) + 3],
|
||||
u_color_stops[(i * 5) + 4]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,17 +51,17 @@ float abs_offset(float offset) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 pixel = get_frag_coord();
|
||||
vec2 pixel = gsk_get_frag_coord();
|
||||
vec2 rel = (center - pixel) / (u_radius);
|
||||
float d = sqrt(dot(rel, rel));
|
||||
|
||||
if (d < abs_offset (color_offsets[0])) {
|
||||
setOutputColor(color_stops[0] * u_alpha);
|
||||
gskSetOutputColor(color_stops[0] * u_alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
if (d > end) {
|
||||
setOutputColor(color_stops[u_num_color_stops - 1] * u_alpha);
|
||||
gskSetOutputColor(color_stops[u_num_color_stops - 1] * u_alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -80,5 +80,5 @@ void main() {
|
||||
}
|
||||
}
|
||||
|
||||
setOutputColor(color * u_alpha);
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ void main() {
|
||||
tp.x = u_texture_rect.x + (wrapped_x * tw);
|
||||
tp.y = u_texture_rect.y + (wrapped_y * th);
|
||||
|
||||
vec4 diffuse = Texture(u_source, tp);
|
||||
vec4 diffuse = GskTexture(u_source, tp);
|
||||
|
||||
setOutputColor(diffuse * u_alpha);
|
||||
gskSetOutputColor(diffuse * u_alpha);
|
||||
}
|
||||
|
@@ -5,8 +5,8 @@ uniform vec2 u_offset;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
_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);
|
||||
@@ -15,30 +15,30 @@ void main() {
|
||||
final_color.rgb *= final_color.a;
|
||||
final_color *= u_alpha;
|
||||
|
||||
RoundedRect inside = create_rect(u_outline_rect);
|
||||
RoundedRect outside = rounded_rect_shrink(inside, vec4(- u_spread));
|
||||
GskRoundedRect inside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread));
|
||||
|
||||
rounded_rect_offset(outside, u_offset);
|
||||
gsk_rounded_rect_offset(outside, u_offset);
|
||||
|
||||
rounded_rect_transform(outside, u_modelview);
|
||||
rounded_rect_transform(inside, u_modelview);
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
rounded_rect_encode(outside, transformed_outside_outline);
|
||||
rounded_rect_encode(inside, transformed_inside_outline);
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = get_frag_coord();
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), frag) -
|
||||
rounded_rect_coverage(decode_rect(transformed_inside_outline), frag),
|
||||
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);
|
||||
|
||||
setOutputColor(final_color * alpha);
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
|
||||
|
@@ -256,6 +256,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
|
||||
case GSK_NOT_A_RENDER_NODE:
|
||||
g_assert_not_reached ();
|
||||
return;
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_SHADOW_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
|
@@ -91,6 +91,14 @@ struct _GtkSnapshotState {
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
} clip;
|
||||
struct {
|
||||
GskGLShader *shader;
|
||||
GBytes *args;
|
||||
graphene_rect_t bounds;
|
||||
int n_children;
|
||||
int node_idx;
|
||||
GskRenderNode **nodes;
|
||||
} glshader;
|
||||
struct {
|
||||
GskRoundedRect bounds;
|
||||
} rounded_clip;
|
||||
@@ -812,6 +820,119 @@ gtk_snapshot_push_clip (GtkSnapshot *snapshot,
|
||||
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &state->data.clip.bounds);
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
gtk_snapshot_collect_gl_shader (GtkSnapshot *snapshot,
|
||||
GtkSnapshotState *state,
|
||||
GskRenderNode **nodes,
|
||||
guint n_nodes)
|
||||
{
|
||||
GskRenderNode *shader_node = NULL, *child_node;
|
||||
GdkRGBA transparent = { 0, 0, 0, 0 };
|
||||
|
||||
child_node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
|
||||
|
||||
if (child_node == NULL)
|
||||
child_node = gsk_color_node_new (&transparent, &state->data.glshader.bounds);
|
||||
|
||||
state->data.glshader.nodes[state->data.glshader.node_idx] = child_node;
|
||||
|
||||
if (state->data.glshader.node_idx != state->data.glshader.n_children - 1)
|
||||
return NULL; /* Not last */
|
||||
|
||||
/* This is the last pop */
|
||||
|
||||
shader_node = NULL;
|
||||
|
||||
if (state->data.glshader.bounds.size.width != 0 &&
|
||||
state->data.glshader.bounds.size.height != 0)
|
||||
{
|
||||
shader_node = gsk_gl_shader_node_new (state->data.glshader.shader,
|
||||
&state->data.glshader.bounds,
|
||||
state->data.glshader.args,
|
||||
&state->data.glshader.nodes[0],
|
||||
state->data.glshader.n_children);
|
||||
}
|
||||
|
||||
g_object_unref (state->data.glshader.shader);
|
||||
g_bytes_unref (state->data.glshader.args);
|
||||
for (guint i = 0; i < state->data.glshader.n_children; i++)
|
||||
gsk_render_node_unref (state->data.glshader.nodes[i]);
|
||||
g_free (state->data.glshader.nodes);
|
||||
|
||||
return shader_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_snapshot_push_gl_shader:
|
||||
* @snapshot: a #GtkSnapshot
|
||||
* @shader: The code to run
|
||||
* @bounds: the rectangle to render into
|
||||
* @take_args: (transfer full): Data block with arguments for the shader.
|
||||
* @n_children: The number of extra nodes given as argument to the shader as textures.
|
||||
*
|
||||
* Push a #GskGLShaderNode with a specific #GskGLShader and a set of uniform values
|
||||
* to use while rendering. Additionally this takes a list of @n_children other nodes
|
||||
* which will be passed to the #GskGLShaderNode.
|
||||
*
|
||||
* The @take_args argument is a block of data to use for uniform
|
||||
* input, as per types and offsets defined by the @shader. Normally this is
|
||||
* generated by gsk_gl_shader_format_args() or #GskGLShaderArgBuilder.
|
||||
* The snapshotter takes ownership of @take_args, so the caller should not free it
|
||||
* after this.
|
||||
*
|
||||
* If the renderer doesn't support GL shaders, or if there is any problem when
|
||||
* compiling the shader, then the node will draw pink. You should use
|
||||
* gsk_gl_shader_try_compile_for() to ensure the @shader will work for the renderer
|
||||
* before using it.
|
||||
*
|
||||
* If @n_children > 0, then it is expected that you (after the fallback call
|
||||
* gtk_snapshot_pop() @n_children times. Each of these will generate a node that
|
||||
* is added as a child to the gl shader node, which in turn will render these to
|
||||
* textures and pass as arguments to the shader.
|
||||
*
|
||||
* For details on how to write shaders, see #GskGLShader.
|
||||
*/
|
||||
void
|
||||
gtk_snapshot_push_gl_shader (GtkSnapshot *snapshot,
|
||||
GskGLShader *shader,
|
||||
const graphene_rect_t *bounds,
|
||||
GBytes *take_args,
|
||||
int n_children)
|
||||
{
|
||||
GtkSnapshotState *state;
|
||||
float scale_x, scale_y, dx, dy;
|
||||
GskRenderNode **nodes;
|
||||
int node_idx;
|
||||
graphene_rect_t transformed_bounds;
|
||||
|
||||
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
|
||||
|
||||
state = gtk_snapshot_push_state (snapshot,
|
||||
gtk_snapshot_get_current_state (snapshot)->transform,
|
||||
gtk_snapshot_collect_gl_shader);
|
||||
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &transformed_bounds);
|
||||
state->data.glshader.bounds = transformed_bounds;
|
||||
state->data.glshader.shader = g_object_ref (shader);
|
||||
state->data.glshader.args = take_args; /* Takes ownership */
|
||||
state->data.glshader.n_children = n_children;
|
||||
nodes = g_new0 (GskRenderNode *, n_children);
|
||||
node_idx = n_children-1; /* We pop in reverse order */
|
||||
|
||||
state->data.glshader.node_idx = node_idx--;
|
||||
state->data.glshader.nodes = nodes;
|
||||
|
||||
for (int i = 0; i < n_children-1; i++)
|
||||
{
|
||||
state = gtk_snapshot_push_state (snapshot,
|
||||
gtk_snapshot_get_current_state (snapshot)->transform,
|
||||
gtk_snapshot_collect_gl_shader);
|
||||
state->data.glshader.node_idx = node_idx--;
|
||||
state->data.glshader.n_children = n_children;
|
||||
state->data.glshader.nodes = nodes;
|
||||
state->data.glshader.bounds = transformed_bounds;
|
||||
}
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
gtk_snapshot_collect_rounded_clip (GtkSnapshot *snapshot,
|
||||
GtkSnapshotState *state,
|
||||
|
@@ -99,6 +99,12 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_push_cross_fade (GtkSnapshot *snapshot,
|
||||
double progress);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_push_gl_shader (GtkSnapshot *snapshot,
|
||||
GskGLShader *shader,
|
||||
const graphene_rect_t *bounds,
|
||||
GBytes *take_args,
|
||||
int n_children);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_pop (GtkSnapshot *snapshot);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
@@ -171,6 +171,25 @@ create_list_model_for_render_node (GskRenderNode *node)
|
||||
return create_render_node_list_model ((GskRenderNode *[2]) { gsk_cross_fade_node_get_start_child (node),
|
||||
gsk_cross_fade_node_get_end_child (node) }, 2);
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
{
|
||||
GListStore *store = g_list_store_new (GDK_TYPE_PAINTABLE);
|
||||
|
||||
for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i++)
|
||||
{
|
||||
GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
|
||||
graphene_rect_t bounds;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
gsk_render_node_get_bounds (child, &bounds);
|
||||
paintable = gtk_render_node_paintable_new (child, &bounds);
|
||||
g_list_store_append (store, paintable);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
{
|
||||
GListStore *store;
|
||||
@@ -270,6 +289,8 @@ node_type_name (GskRenderNodeType type)
|
||||
return "Text";
|
||||
case GSK_BLUR_NODE:
|
||||
return "Blur";
|
||||
case GSK_GL_SHADER_NODE:
|
||||
return "GL Shader";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +322,7 @@ node_name (GskRenderNode *node)
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GL_SHADER_NODE:
|
||||
return g_strdup (node_type_name (gsk_render_node_get_node_type (node)));
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
@@ -511,6 +533,34 @@ add_color_row (GtkListStore *store,
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
static void
|
||||
add_int_row (GtkListStore *store,
|
||||
const char *name,
|
||||
int value)
|
||||
{
|
||||
char *text = g_strdup_printf ("%d", value);
|
||||
add_text_row (store, name, text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
add_uint_row (GtkListStore *store,
|
||||
const char *name,
|
||||
guint value)
|
||||
{
|
||||
char *text = g_strdup_printf ("%u", value);
|
||||
add_text_row (store, name, text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
add_boolean_row (GtkListStore *store,
|
||||
const char *name,
|
||||
gboolean value)
|
||||
{
|
||||
add_text_row (store, name, value ? "TRUE" : "FALSE");
|
||||
}
|
||||
|
||||
static void
|
||||
add_float_row (GtkListStore *store,
|
||||
const char *name,
|
||||
@@ -759,6 +809,92 @@ populate_render_node_properties (GtkListStore *store,
|
||||
add_float_row (store, "Radius", gsk_blur_node_get_radius (node));
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
{
|
||||
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
|
||||
GBytes *args = gsk_gl_shader_node_get_args (node);
|
||||
int i;
|
||||
|
||||
add_int_row (store, "Required textures", gsk_gl_shader_get_n_required_textures (shader));
|
||||
for (i = 0; i < gsk_gl_shader_get_n_uniforms (shader); i++)
|
||||
{
|
||||
const char *name;
|
||||
char *title;
|
||||
|
||||
name = gsk_gl_shader_get_uniform_name (shader, i);
|
||||
title = g_strdup_printf ("Uniform %s", name);
|
||||
|
||||
switch (gsk_gl_shader_get_uniform_type (shader, i))
|
||||
{
|
||||
case GSK_GL_UNIFORM_TYPE_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_FLOAT:
|
||||
add_float_row (store, title,
|
||||
gsk_gl_shader_get_arg_float (shader, args, i));
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_INT:
|
||||
add_int_row (store, title,
|
||||
gsk_gl_shader_get_arg_int (shader, args, i));
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_UINT:
|
||||
add_uint_row (store, title,
|
||||
gsk_gl_shader_get_arg_uint (shader, args, i));
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_BOOL:
|
||||
add_boolean_row (store, title,
|
||||
gsk_gl_shader_get_arg_bool (shader, args, i));
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC2:
|
||||
{
|
||||
graphene_vec2_t v;
|
||||
gsk_gl_shader_get_arg_vec2 (shader, args, i, &v);
|
||||
float x = graphene_vec2_get_x (&v);
|
||||
float y = graphene_vec2_get_x (&v);
|
||||
char *s = g_strdup_printf ("%.2f %.2f", x, y);
|
||||
add_text_row (store, title, s);
|
||||
g_free (s);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC3:
|
||||
{
|
||||
graphene_vec3_t v;
|
||||
gsk_gl_shader_get_arg_vec3 (shader, args, i, &v);
|
||||
float x = graphene_vec3_get_x (&v);
|
||||
float y = graphene_vec3_get_y (&v);
|
||||
float z = graphene_vec3_get_z (&v);
|
||||
char *s = g_strdup_printf ("%.2f %.2f %.2f", x, y, z);
|
||||
add_text_row (store, title, s);
|
||||
g_free (s);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GL_UNIFORM_TYPE_VEC4:
|
||||
{
|
||||
graphene_vec4_t v;
|
||||
gsk_gl_shader_get_arg_vec4 (shader, args, i, &v);
|
||||
float x = graphene_vec4_get_x (&v);
|
||||
float y = graphene_vec4_get_y (&v);
|
||||
float z = graphene_vec4_get_z (&v);
|
||||
float w = graphene_vec4_get_w (&v);
|
||||
char *s = g_strdup_printf ("%.2f %.2f %.2f %.2f", x, y, z, w);
|
||||
add_text_row (store, title, s);
|
||||
g_free (s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
g_free (title);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
{
|
||||
const GdkRGBA *color = gsk_inset_shadow_node_peek_color (node);
|
||||
|
@@ -188,6 +188,7 @@ endforeach
|
||||
tests = [
|
||||
['rounded-rect'],
|
||||
['transform'],
|
||||
['shader'],
|
||||
]
|
||||
|
||||
test_cargs = []
|
||||
|
215
testsuite/gsk/shader.c
Normal file
215
testsuite/gsk/shader.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* shader fragment as found in nature */
|
||||
const char shader0[] =
|
||||
"// author: bobylito\n"
|
||||
"// license: MIT\n"
|
||||
"const float SQRT_2 = 1.414213562373;"
|
||||
"uniform float dots;// = 20.0;"
|
||||
"uniform vec2 center; //= vec2(0, 0);"
|
||||
""
|
||||
"vec4 transition(vec2 uv) {"
|
||||
" bool nextImage = distance(fract(uv * dots), vec2(0.5, 0.5)) < ( progress / distance(uv, center));"
|
||||
" return nextImage ? getToColor(uv) : getFromColor(uv);"
|
||||
"}";
|
||||
|
||||
/* Same shader, with our preamble added, and with newlines
|
||||
* to make the regex happy. Added a variety of uniforms to
|
||||
* exercise the parser.
|
||||
*/
|
||||
const char shader1[] =
|
||||
"uniform float progress;\n"
|
||||
"uniform sampler2D u_texture1;\n"
|
||||
"uniform sampler2D u_texture2;\n"
|
||||
""
|
||||
"vec4 getFromColor (vec2 uv) {\n"
|
||||
" return GskTexture(u_texture1, uv);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"vec4 getToColor (vec2 uv) {\n"
|
||||
" return GskTexture(u_texture2, uv);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"// author: bobylito\n"
|
||||
"// license: MIT\n"
|
||||
"const float SQRT_2 = 1.414213562373;\n"
|
||||
"uniform float dots;// = 20.0;\n"
|
||||
"uniform vec2 center; //= vec2(0, 0);\n"
|
||||
"\n"
|
||||
"uniform int test1 = -2;\n"
|
||||
"uniform uint test2 = 2; \n"
|
||||
"uniform bool test3;\n"
|
||||
"uniform vec3 test4;\n"
|
||||
"uniform vec4 test5;\n"
|
||||
"\n"
|
||||
"vec4 transition(vec2 uv) {\n"
|
||||
" bool nextImage = distance(fract(uv * dots), vec2(0.5, 0.5)) < ( progress / distance(uv, center));\n"
|
||||
" return nextImage ? getToColor(uv) : getFromColor(uv);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)\n"
|
||||
"{\n"
|
||||
" fragColor = transition(uv);\n"
|
||||
"}\n";
|
||||
|
||||
static void
|
||||
test_create_simple (void)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GskGLShader *shader;
|
||||
|
||||
bytes = g_bytes_new_static (shader1, sizeof (shader1));
|
||||
shader = gsk_gl_shader_new_from_bytes (bytes);
|
||||
g_assert_nonnull (shader);
|
||||
|
||||
g_assert_cmpint (gsk_gl_shader_get_n_required_textures (shader), ==, 2);
|
||||
g_assert_cmpint (gsk_gl_shader_get_n_uniforms (shader), ==, 8);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 0), ==, "progress");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 0), ==, GSK_GL_UNIFORM_TYPE_FLOAT);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 1), ==, "dots");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 1), ==, GSK_GL_UNIFORM_TYPE_FLOAT);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 2), ==, "center");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 2), ==, GSK_GL_UNIFORM_TYPE_VEC2);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 3), ==, "test1");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 3), ==, GSK_GL_UNIFORM_TYPE_INT);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 4), ==, "test2");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 4), ==, GSK_GL_UNIFORM_TYPE_UINT);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 5), ==, "test3");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 5), ==, GSK_GL_UNIFORM_TYPE_BOOL);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 6), ==, "test4");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 6), ==, GSK_GL_UNIFORM_TYPE_VEC3);
|
||||
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 7), ==, "test5");
|
||||
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 7), ==, GSK_GL_UNIFORM_TYPE_VEC4);
|
||||
|
||||
g_object_unref (shader);
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
test_create_data (void)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GskGLShader *shader;
|
||||
GskShaderArgsBuilder *builder;
|
||||
graphene_vec2_t v2, vv2;
|
||||
graphene_vec3_t v3, vv3;
|
||||
graphene_vec4_t v4, vv4;
|
||||
|
||||
bytes = g_bytes_new_static (shader1, sizeof (shader1));
|
||||
shader = gsk_gl_shader_new_from_bytes (bytes);
|
||||
g_assert_nonnull (shader);
|
||||
g_clear_pointer (&bytes, g_bytes_unref);
|
||||
|
||||
builder = gsk_gl_shader_build_args (shader);
|
||||
g_assert_nonnull (builder);
|
||||
|
||||
graphene_vec2_init (&v2, 20, 30);
|
||||
graphene_vec3_init (&v3, -1, -2, -3);
|
||||
graphene_vec4_init (&v4, 100, 0, -100, 10);
|
||||
gsk_shader_args_builder_set_float (builder, 0, 0.5);
|
||||
gsk_shader_args_builder_set_float (builder, 1, 20.0);
|
||||
gsk_shader_args_builder_set_vec2 (builder, 2, &v2);
|
||||
gsk_shader_args_builder_set_int (builder, 3, -99);
|
||||
gsk_shader_args_builder_set_uint (builder, 4, 99);
|
||||
gsk_shader_args_builder_set_bool (builder, 5, 1);
|
||||
gsk_shader_args_builder_set_vec3 (builder, 6, &v3);
|
||||
gsk_shader_args_builder_set_vec4 (builder, 7, &v4);
|
||||
|
||||
bytes = gsk_shader_args_builder_finish (builder);
|
||||
|
||||
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, bytes, 0), ==, 0.5);
|
||||
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, bytes, 1), ==, 20.0);
|
||||
gsk_gl_shader_get_arg_vec2 (shader, bytes, 2, &vv2);
|
||||
g_assert_true (graphene_vec2_equal (&v2, &vv2));
|
||||
|
||||
g_assert_cmpint (gsk_gl_shader_get_arg_int (shader, bytes, 3), ==, -99);
|
||||
g_assert_cmpuint (gsk_gl_shader_get_arg_uint (shader, bytes, 4), ==, 99);
|
||||
g_assert_cmpint (gsk_gl_shader_get_arg_bool (shader, bytes, 5), ==, 1);
|
||||
|
||||
gsk_gl_shader_get_arg_vec3 (shader, bytes, 6, &vv3);
|
||||
g_assert_true (graphene_vec3_equal (&v3, &vv3));
|
||||
gsk_gl_shader_get_arg_vec4 (shader, bytes, 7, &vv4);
|
||||
g_assert_true (graphene_vec4_equal (&v4, &vv4));
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
gsk_shader_args_builder_free (builder);
|
||||
|
||||
g_object_unref (shader);
|
||||
}
|
||||
|
||||
static void
|
||||
test_format_args (void)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GskGLShader *shader;
|
||||
graphene_vec2_t v2, vv2;
|
||||
graphene_vec3_t v3, vv3;
|
||||
graphene_vec4_t v4, vv4;
|
||||
float f1, f2;
|
||||
GBytes *args;
|
||||
|
||||
bytes = g_bytes_new_static (shader1, sizeof (shader1));
|
||||
shader = gsk_gl_shader_new_from_bytes (bytes);
|
||||
g_assert_nonnull (shader);
|
||||
g_clear_pointer (&bytes, g_bytes_unref);
|
||||
|
||||
graphene_vec2_init (&v2, 20, 30);
|
||||
graphene_vec3_init (&v3, -1, -2, -3);
|
||||
graphene_vec4_init (&v4, 100, 0, -100, 10);
|
||||
|
||||
f1 = 0.5;
|
||||
f2 = 20.0;
|
||||
args = gsk_gl_shader_format_args (shader,
|
||||
"progress", &f1,
|
||||
"dots", &f2,
|
||||
"center", &v2,
|
||||
"test4", &v3,
|
||||
"test5", &v4,
|
||||
NULL);
|
||||
|
||||
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, args, 0), ==, 0.5);
|
||||
g_assert_cmpfloat (gsk_gl_shader_get_arg_float (shader, args, 1), ==, 20.0);
|
||||
gsk_gl_shader_get_arg_vec2 (shader, args, 2, &vv2);
|
||||
g_assert_true (graphene_vec2_equal (&v2, &vv2));
|
||||
gsk_gl_shader_get_arg_vec3 (shader, args, 6, &vv3);
|
||||
g_assert_true (graphene_vec3_equal (&v3, &vv3));
|
||||
gsk_gl_shader_get_arg_vec4 (shader, args, 7, &vv4);
|
||||
g_assert_true (graphene_vec4_equal (&v4, &vv4));
|
||||
|
||||
g_bytes_unref (args);
|
||||
|
||||
g_object_unref (shader);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
gtk_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/shader/create/simple", test_create_simple);
|
||||
g_test_add_func ("/shader/create/data", test_create_data);
|
||||
g_test_add_func ("/shader/format-args", test_format_args);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
Reference in New Issue
Block a user