mirror of
https://github.com/brl/mutter.git
synced 2024-11-27 02:20:43 -05:00
2994de63ef
implementation of a box-blur shader from Gwenole Beauchesne that should work on GLSL implementing low-end IGPs not implementing dynamic branching. The original code used crashed some of these due to bugs in drivers or similar. Resolves bug #710.
308 lines
9.2 KiB
C
308 lines
9.2 KiB
C
/*#define TEST_GROUP */
|
|
|
|
#include <clutter/clutter.h>
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <glib.h>
|
|
|
|
/* Dynamic branching appeared in "Shader Model 3.0" that low-end IGPs
|
|
* don't support.
|
|
*/
|
|
#define GPU_SUPPORTS_DYNAMIC_BRANCHING 0
|
|
|
|
typedef struct
|
|
{
|
|
gchar *name;
|
|
gchar *source;
|
|
} ShaderSource;
|
|
|
|
static ShaderSource shaders[]=
|
|
{
|
|
{"brightness-contrast",
|
|
|
|
"uniform float brightness;"
|
|
"uniform float contrast;"
|
|
"uniform sampler2DRect pend_s3_tex;"
|
|
""
|
|
"void main()"
|
|
"{"
|
|
" vec4 pend_s4_result;"
|
|
" pend_s4_result = texture2DRect(pend_s3_tex, gl_TexCoord[0].xy);"
|
|
" pend_s4_result.x = (pend_s4_result.x - 0.5)*contrast + brightness + 0.5;"
|
|
" pend_s4_result.y = (pend_s4_result.y - 0.5)*contrast + brightness + 0.5;"
|
|
" pend_s4_result.z = (pend_s4_result.z - 0.5)*contrast + brightness + 0.5;"
|
|
" gl_FragColor = pend_s4_result;"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}",
|
|
},
|
|
{"box-blur",
|
|
#if GPU_SUPPORTS_DYNAMIC_BRANCHING
|
|
"uniform float radius ;"
|
|
"uniform sampler2DRect rectTexture;"
|
|
""
|
|
"void main()"
|
|
"{"
|
|
" vec4 color = texture2DRect(rectTexture, gl_TexCoord[0].st);"
|
|
" float u;"
|
|
" float v;"
|
|
" int count = 1;"
|
|
" for (u=-radius;u<radius;u++)"
|
|
" for (v=-radius;v<radius;v++)"
|
|
" {"
|
|
" color += texture2DRect(rectTexture, vec2(gl_TexCoord[0].s + u * 2.0, gl_TexCoord[0].t +v * 2.0));"
|
|
" count ++;"
|
|
" }"
|
|
""
|
|
" gl_FragColor = color / float(count);"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}"
|
|
#else
|
|
"uniform sampler2DRect rectTexture;"
|
|
"vec4 tex_load(const vec2 coord)"
|
|
"{"
|
|
" return texture2DRect (rectTexture, gl_TexCoord[0].st + coord * 2.0);"
|
|
"}"
|
|
""
|
|
"void main()"
|
|
"{"
|
|
" vec4 color;"
|
|
" float count = 1.0;"
|
|
""
|
|
" color = texture2DRect (rectTexture, gl_TexCoord[0].st);"
|
|
" color += tex_load (vec2 (-1.0, -1.0)); count++;"
|
|
" color += tex_load (vec2 (-1.0, 0.0)); count++;"
|
|
" color += tex_load (vec2 (-1.0, 1.0)); count++;"
|
|
" color += tex_load (vec2 ( 0.0, -1.0)); count++;"
|
|
" color += tex_load (vec2 ( 0.0, 0.0)); count++;"
|
|
" color += tex_load (vec2 ( 0.0, 1.0)); count++;"
|
|
" color += tex_load (vec2 ( 1.0, -1.0)); count++;"
|
|
" color += tex_load (vec2 ( 1.0, 0.0)); count++;"
|
|
" color += tex_load (vec2 ( 1.0, 1.0)); count++;"
|
|
""
|
|
" gl_FragColor = color / count;"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}"
|
|
#endif
|
|
},
|
|
{"invert",
|
|
|
|
"uniform sampler2DRect tex;\n"
|
|
"void main ()\n"
|
|
"{\n"
|
|
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));\n"
|
|
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) - color;\n"
|
|
" gl_FragColor.a = color.a;\n"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}"
|
|
},
|
|
{"brightness-contrast",
|
|
|
|
"uniform sampler2DRect tex;"
|
|
"uniform float brightness;"
|
|
"uniform float contrast;"
|
|
"void main ()"
|
|
"{"
|
|
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));"
|
|
" color.r = (color.r - 0.5) * contrast + brightness + 0.5;"
|
|
" color.g = (color.g - 0.5) * contrast + brightness + 0.5;"
|
|
" color.b = (color.b - 0.5) * contrast + brightness + 0.5;"
|
|
" gl_FragColor = color;"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}",
|
|
},
|
|
{"gray",
|
|
"uniform sampler2DRect tex;"
|
|
"void main ()"
|
|
"{"
|
|
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));"
|
|
" float avg = (color.r + color.g + color.b) / 3.0;"
|
|
" color.r = avg;"
|
|
" color.g = avg;"
|
|
" color.b = avg;"
|
|
" gl_FragColor = color;"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}",
|
|
},
|
|
{"combined-mirror",
|
|
"uniform sampler2DRect tex;"
|
|
"void main ()"
|
|
"{"
|
|
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));"
|
|
" vec4 colorB = texture2DRect (tex, vec2(gl_TexCoord[0].ts));"
|
|
" float avg = (color.r + color.g + color.b) / 3.0;"
|
|
" color.r = avg;"
|
|
" color.g = avg;"
|
|
" color.b = avg;"
|
|
" color = (color + colorB)/2.0;"
|
|
" gl_FragColor = color;"
|
|
" gl_FragColor = gl_FragColor * gl_Color;"
|
|
"}",
|
|
},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
static gint shader_no = 0;
|
|
|
|
static gboolean
|
|
button_release_cb (ClutterActor *actor,
|
|
ClutterEvent *event,
|
|
gpointer data)
|
|
{
|
|
gint new_no;
|
|
|
|
if (event->button.button == 1)
|
|
{
|
|
new_no = shader_no - 1;
|
|
}
|
|
else
|
|
{
|
|
new_no = shader_no + 1;
|
|
}
|
|
|
|
if (new_no >= 0 && shaders[new_no].name)
|
|
{
|
|
ClutterShader *shader;
|
|
GError *error;
|
|
shader_no = new_no;
|
|
|
|
g_print ("setting shaders[%i] named '%s'\n",
|
|
shader_no,
|
|
shaders[shader_no].name);
|
|
|
|
shader = clutter_shader_new ();
|
|
|
|
error = NULL;
|
|
g_object_set (G_OBJECT (shader), "fragment-source", shaders[shader_no].source, NULL);
|
|
|
|
/* try to bind the shader, provoking an error we catch if there is issues
|
|
* with the shader sources we've provided. At a later stage it should be possible to
|
|
* iterate through a set of alternate shader sources (glsl -> asm -> cg?) and the one
|
|
* that succesfully compiles is used.
|
|
*/
|
|
clutter_shader_bind (shader, &error);
|
|
|
|
if (error)
|
|
{
|
|
g_print ("unable to set shaders[%i] named '%s': %s",
|
|
shader_no, shaders[shader_no].name,
|
|
error->message);
|
|
g_error_free (error);
|
|
clutter_actor_set_shader (actor, NULL);
|
|
}
|
|
else
|
|
{
|
|
clutter_actor_set_shader (actor, NULL);
|
|
clutter_actor_set_shader (actor, shader);
|
|
clutter_actor_set_shader_param (actor, "radius", 3.0);
|
|
clutter_actor_set_shader_param (actor, "brightness", 0.4);
|
|
clutter_actor_set_shader_param (actor, "contrast", -1.9);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
gint
|
|
main (gint argc,
|
|
gchar *argv[])
|
|
{
|
|
ClutterTimeline *timeline;
|
|
ClutterActor *actor;
|
|
ClutterActor *stage;
|
|
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
|
|
ClutterShader *shader;
|
|
GdkPixbuf *pixbuf;
|
|
GError *error;
|
|
|
|
clutter_init (&argc, &argv);
|
|
|
|
stage = clutter_stage_get_default ();
|
|
clutter_actor_set_size (stage, 512, 384);
|
|
|
|
g_print ("applying shaders[%i] named '%s'\n",
|
|
shader_no,
|
|
shaders[shader_no].name);
|
|
|
|
shader = clutter_shader_new ();
|
|
|
|
error = NULL;
|
|
clutter_shader_set_fragment_source (shader, shaders[shader_no].source, -1);
|
|
clutter_shader_bind (shader, &error);
|
|
if (error)
|
|
{
|
|
g_print ("unable to load shaders[%d] named '%s': %s\n",
|
|
shader_no,
|
|
shaders[shader_no].name,
|
|
error->message);
|
|
g_error_free (error);
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
pixbuf = gdk_pixbuf_new_from_file ("redhand.png", &error);
|
|
if (!pixbuf)
|
|
g_error("pixbuf load failed: %s", error ? error->message : "Unknown");
|
|
|
|
clutter_stage_set_title (CLUTTER_STAGE (stage), "Shader Test");
|
|
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
|
|
|
|
/* Create a timeline to manage animation */
|
|
timeline = clutter_timeline_new (360, 60); /* num frames, fps */
|
|
g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */
|
|
|
|
#ifndef TEST_GROUP
|
|
actor = clutter_texture_new_from_pixbuf (pixbuf);
|
|
#else
|
|
actor = clutter_group_new ();
|
|
{
|
|
ClutterActor *child1, *child2, *child3, *child4;
|
|
ClutterColor color = { 0xff, 0x22, 0x66, 0x99 };
|
|
|
|
child1 = clutter_texture_new_from_pixbuf (pixbuf);
|
|
child2 = clutter_texture_new_from_pixbuf (pixbuf);
|
|
child3 = clutter_rectangle_new ();
|
|
child4 = clutter_label_new_with_text ("Sans 20px", "Shady stuff");
|
|
|
|
clutter_rectangle_set_color (child3, &color);
|
|
clutter_actor_set_size (child3, 50, 50);
|
|
clutter_actor_set_position (child1, 0, 0);
|
|
clutter_actor_set_position (child2, 50, 100);
|
|
clutter_actor_set_position (child3, 30, -30);
|
|
clutter_actor_set_position (child4, -50, 20);
|
|
|
|
clutter_group_add (CLUTTER_GROUP (actor), child1);
|
|
clutter_group_add (CLUTTER_GROUP (actor), child2);
|
|
clutter_group_add (CLUTTER_GROUP (actor), child3);
|
|
clutter_group_add (CLUTTER_GROUP (actor), child4);
|
|
|
|
clutter_actor_show_all (actor);
|
|
}
|
|
#endif
|
|
|
|
clutter_actor_set_shader (actor, shader);
|
|
clutter_actor_set_position (actor, 100, 100);
|
|
|
|
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
|
|
|
|
|
|
clutter_actor_set_shader_param (actor, "brightness", 0.4);
|
|
clutter_actor_set_shader_param (actor, "contrast", -1.9);
|
|
|
|
clutter_actor_set_reactive (actor, TRUE);
|
|
g_signal_connect (actor, "button-release-event",
|
|
G_CALLBACK (button_release_cb), NULL);
|
|
|
|
/*clutter_actor_set_opacity (actor, 0x77);*/
|
|
|
|
/* Show everying ( and map window ) */
|
|
clutter_actor_show_all (stage);
|
|
|
|
/* and start it */
|
|
clutter_timeline_start (timeline);
|
|
|
|
clutter_main ();
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|