mutter/src/tests/clutter/interactive/test-cogl-shader-glsl.c
Robert Mader 8e172aeecb cleanup: Use g_clear_handle_id() for g_source_remove()
It makes sure we do not forget to zero the id and lets us avoid
zero checks before. We use it for all new code, lets clean up the
existing code base.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/947
2019-11-22 01:27:40 +01:00

348 lines
10 KiB
C

#include <clutter/clutter.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
typedef struct
{
const char *name;
const char *source;
} ShaderSource;
int
test_cogl_shader_glsl_main (int argc, char *argv[]);
/* a couple of boilerplate defines that are common amongst all the
* sample shaders
*/
/* FRAGMENT_SHADER_BEGIN: generate boilerplate with a local vec4 color already
* initialized, from a sampler2D in a variable tex.
*/
#define FRAGMENT_SHADER_VARS \
"uniform sampler2D tex;" \
"uniform float x_step, y_step;"
#define FRAGMENT_SHADER_BEGIN \
"void main (){" \
" vec4 color = texture2D (tex, vec2(cogl_tex_coord_in[0]));"
/* FRAGMENT_SHADER_END: apply the changed color to the output buffer correctly
* blended with the gl specified color (makes the opacity of actors work
* correctly).
*/
#define FRAGMENT_SHADER_END \
" cogl_color_out = color;" \
" cogl_color_out = cogl_color_out * cogl_color_in;" \
"}"
static ShaderSource shaders[]=
{
{"brightness-contrast",
FRAGMENT_SHADER_VARS
"uniform float brightness, contrast;"
FRAGMENT_SHADER_BEGIN
" color.rgb /= color.a;"
" color.rgb = (color.rgb - vec3(0.5, 0.5, 0.5)) * contrast + "
"vec3 (brightness + 0.5, brightness + 0.5, brightness + 0.5);"
" color.rgb *= color.a;"
FRAGMENT_SHADER_END
},
{"box-blur",
FRAGMENT_SHADER_VARS
"vec4 get_rgba_rel(sampler2D tex, float dx, float dy)"
"{"
" return texture2D (tex, cogl_tex_coord_in[0].st "
" + vec2(dx, dy) * 2.0);"
"}"
FRAGMENT_SHADER_BEGIN
" float count = 1.0;"
" color += get_rgba_rel (tex, -x_step, -y_step); count++;"
" color += get_rgba_rel (tex, -x_step, 0.0); count++;"
" color += get_rgba_rel (tex, -x_step, y_step); count++;"
" color += get_rgba_rel (tex, 0.0, -y_step); count++;"
" color += get_rgba_rel (tex, 0.0, 0.0); count++;"
" color += get_rgba_rel (tex, 0.0, y_step); count++;"
" color += get_rgba_rel (tex, x_step, -y_step); count++;"
" color += get_rgba_rel (tex, x_step, 0.0); count++;"
" color += get_rgba_rel (tex, x_step, y_step); count++;"
" color = color / count;"
FRAGMENT_SHADER_END
},
{"invert",
FRAGMENT_SHADER_VARS
FRAGMENT_SHADER_BEGIN
" color.rgb /= color.a;"
" color.rgb = vec3(1.0, 1.0, 1.0) - color.rgb;\n"
" color.rgb *= color.a;"
FRAGMENT_SHADER_END
},
{"brightness-contrast",
FRAGMENT_SHADER_VARS
"uniform float brightness;"
"uniform float contrast;"
FRAGMENT_SHADER_BEGIN
" color.rgb /= color.a;"
" 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;"
" color.rgb *= color.a;"
FRAGMENT_SHADER_END
},
{"gray",
FRAGMENT_SHADER_VARS
FRAGMENT_SHADER_BEGIN
" float avg = (color.r + color.g + color.b) / 3.0;"
" color.r = avg;"
" color.g = avg;"
" color.b = avg;"
FRAGMENT_SHADER_END
},
{"combined-mirror",
FRAGMENT_SHADER_VARS
FRAGMENT_SHADER_BEGIN
" vec4 colorB = texture2D (tex, vec2(cogl_tex_coord_in[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;"
FRAGMENT_SHADER_END
},
{"edge-detect",
FRAGMENT_SHADER_VARS
"float get_avg_rel(sampler2D texB, float dx, float dy)"
"{"
" vec4 colorB = texture2D (texB, cogl_tex_coord_in[0].st + vec2(dx, dy));"
" return (colorB.r + colorB.g + colorB.b) / 3.0;"
"}"
FRAGMENT_SHADER_BEGIN
" mat3 sobel_h = mat3( 1.0, 2.0, 1.0,"
" 0.0, 0.0, 0.0,"
" -1.0, -2.0, -1.0);"
" mat3 sobel_v = mat3( 1.0, 0.0, -1.0,"
" 2.0, 0.0, -2.0,"
" 1.0, 0.0, -1.0);"
" mat3 map = mat3( get_avg_rel(tex, -x_step, -y_step),"
" get_avg_rel(tex, -x_step, 0.0),"
" get_avg_rel(tex, -x_step, y_step),"
" get_avg_rel(tex, 0.0, -y_step),"
" get_avg_rel(tex, 0.0, 0.0),"
" get_avg_rel(tex, 0.0, y_step),"
" get_avg_rel(tex, x_step, -y_step),"
" get_avg_rel(tex, x_step, 0.0),"
" get_avg_rel(tex, x_step, y_step) );"
" mat3 gh = sobel_h * map;"
" mat3 gv = map * sobel_v;"
" float avgh = (gh[0][0] + gh[0][1] + gh[0][2] +"
" gh[1][0] + gh[1][1] + gh[1][2] +"
" gh[2][0] + gh[2][1] + gh[2][2]) / 18.0 + 0.5;"
" float avgv = (gv[0][0] + gv[0][1] + gv[0][2] +"
" gv[1][0] + gv[1][1] + gv[1][2] +"
" gv[2][0] + gv[2][1] + gv[2][2]) / 18.0 + 0.5;"
" float avg = (avgh + avgv) / 2.0;"
" color.r = avg * color.r;"
" color.g = avg * color.g;"
" color.b = avg * color.b;"
FRAGMENT_SHADER_END
}
};
static CoglHandle redhand;
static CoglMaterial *material;
static unsigned int timeout_id = 0;
static int shader_no = 0;
static void
paint_cb (ClutterActor *actor)
{
float stage_width = clutter_actor_get_width (actor);
float stage_height = clutter_actor_get_height (actor);
float image_width = cogl_texture_get_width (redhand);
float image_height = cogl_texture_get_height (redhand);
cogl_set_source (material);
cogl_rectangle (stage_width/2.0f - image_width/2.0f,
stage_height/2.0f - image_height/2.0f,
stage_width/2.0f + image_width/2.0f,
stage_height/2.0f + image_height/2.0f);
}
static void
set_shader_num (int new_no)
{
CoglHandle shader;
CoglHandle program;
int image_width = cogl_texture_get_width (redhand);
int image_height = cogl_texture_get_height (redhand);
int uniform_no;
g_print ("setting shaders[%i] named '%s'\n",
new_no,
shaders[new_no].name);
shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
cogl_shader_source (shader, shaders[new_no].source);
cogl_shader_compile (shader);
program = cogl_create_program ();
cogl_program_attach_shader (program, shader);
cogl_object_unref (shader);
cogl_program_link (program);
uniform_no = cogl_program_get_uniform_location (program, "tex");
cogl_program_set_uniform_1i (program, uniform_no, 0);
uniform_no = cogl_program_get_uniform_location (program, "radius");
cogl_program_set_uniform_1f (program, uniform_no, 3.0);
uniform_no = cogl_program_get_uniform_location (program, "brightness");
cogl_program_set_uniform_1f (program, uniform_no, 0.4);
uniform_no = cogl_program_get_uniform_location (program, "contrast");
cogl_program_set_uniform_1f (program, uniform_no, -1.9);
uniform_no = cogl_program_get_uniform_location (program, "x_step");
cogl_program_set_uniform_1f (program, uniform_no, 1.0f / image_width);
uniform_no = cogl_program_get_uniform_location (program, "y_step");
cogl_program_set_uniform_1f (program, uniform_no, 1.0f / image_height);
cogl_material_set_user_program (material, program);
cogl_object_unref (program);
shader_no = new_no;
}
static gboolean
button_release_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
int new_no;
/* Stop the automatic cycling if the user want to manually control
* which shader to display */
g_clear_handle_id (&timeout_id, g_source_remove);
if (event->button.button == 1)
{
new_no = shader_no - 1;
if (new_no < 0)
new_no = G_N_ELEMENTS (shaders) - 1;
}
else
{
new_no = shader_no + 1;
if (new_no >= G_N_ELEMENTS (shaders))
new_no = 0;
}
set_shader_num (new_no);
return CLUTTER_EVENT_STOP;
}
static gboolean
key_release_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
guint keysym = clutter_event_get_key_symbol (event);
ClutterModifierType mods = clutter_event_get_state (event);
if (keysym == CLUTTER_KEY_q ||
((mods & CLUTTER_SHIFT_MASK) && keysym == CLUTTER_KEY_q))
clutter_main_quit ();
return CLUTTER_EVENT_STOP;
}
static gboolean
timeout_cb (gpointer user_data)
{
shader_no++;
if (shader_no > (G_N_ELEMENTS (shaders) - 1))
shader_no = 0;
set_shader_num (shader_no);
return G_SOURCE_CONTINUE;
}
static gboolean
idle_cb (gpointer data)
{
clutter_actor_queue_redraw (data);
return G_SOURCE_CONTINUE;
}
static gboolean
destroy_window_cb (ClutterStage *stage,
ClutterEvent *event,
gpointer user_data)
{
clutter_main_quit ();
return CLUTTER_EVENT_STOP;
}
G_MODULE_EXPORT int
test_cogl_shader_glsl_main (int argc, char *argv[])
{
ClutterActor *stage;
char *file;
GError *error;
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Assembly Shader Test");
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
error = NULL;
redhand = cogl_texture_new_from_file (file,
COGL_TEXTURE_NO_ATLAS,
COGL_PIXEL_FORMAT_ANY,
&error);
if (redhand == NULL)
g_error ("image load failed: %s", error->message);
material = cogl_material_new ();
cogl_material_set_layer (material, 0, redhand);
set_shader_num (0);
g_signal_connect_after (stage, "paint", G_CALLBACK (paint_cb), NULL);
clutter_actor_set_reactive (stage, TRUE);
g_signal_connect (stage, "button-release-event",
G_CALLBACK (button_release_cb), NULL);
g_signal_connect (stage, "key-release-event",
G_CALLBACK (key_release_cb), NULL);
g_signal_connect (stage, "delete-event",
G_CALLBACK (destroy_window_cb), NULL);
timeout_id = clutter_threads_add_timeout (1000, timeout_cb, NULL);
clutter_threads_add_idle (idle_cb, stage);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}