From f6a1f56031ed0bb404b902db83629732fc788b32 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 5 Aug 2010 15:20:49 +0100 Subject: [PATCH] tests/interactive: Adds a test-cogl-shader-arbfp.c This tests the ARBfp support for cogl_program and cogl_shader using the shaders Chris Lord adapted from test-shader when he was experimenting with adding ARBfp support to clutter back in 2008 (See: http://bugzilla.clutter-project.org/show_bug.cgi?id=1049) --- tests/interactive/Makefile.am | 1 + tests/interactive/test-cogl-shader-arbfp.c | 404 +++++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 tests/interactive/test-cogl-shader-arbfp.c diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am index 0133bedb9..e5882ed32 100644 --- a/tests/interactive/Makefile.am +++ b/tests/interactive/Makefile.am @@ -18,6 +18,7 @@ UNIT_TESTS = \ test-grab.c \ test-fullscreen.c \ test-shader.c \ + test-cogl-shader-arbfp.c \ test-animator.c \ test-state.c \ test-state-animator.c \ diff --git a/tests/interactive/test-cogl-shader-arbfp.c b/tests/interactive/test-cogl-shader-arbfp.c new file mode 100644 index 000000000..20ac90d73 --- /dev/null +++ b/tests/interactive/test-cogl-shader-arbfp.c @@ -0,0 +1,404 @@ +#include + +#include +#include +#include +#include + +typedef struct +{ + char *name; + char *source; +} ShaderSource; + +static ShaderSource shaders[]= + { + /*{"brightness-contrast", + FRAGMENT_SHADER_VARS + "uniform float brightness, contrast;" + FRAGMENT_SHADER_BEGIN + " color.rgb = (color.rgb - vec3(0.5, 0.5, 0.5)) * contrast + " + "vec3 (brightness + 0.5, brightness + 0.5, brightness + 0.5);" + FRAGMENT_SHADER_END + },*/ + {"brightness-contrast", + "!!ARBfp1.0\n" + "PARAM bc = program.local[0];" + "TEMP color;" + "TEMP color2;" + "TEX color.rgba, fragment.texcoord[0], texture[0], 2D;" + "SUB color.rgb, color, 0.5;" + "MUL color2, color, bc.w;" + "ADD color.rgb, color2, bc.z;" + "MOV result.color, color;" + "END" + }, + + /*{"box-blur", + FRAGMENT_SHADER_VARS + + "vec4 get_rgba_rel(sampler2D tex, float dx, float dy)" + "{" + " return texture2D (tex, " TEX_COORD ".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 + },*/ + {"box-blur", + "!!ARBfp1.0\n" + "PARAM params = program.local[0];" + "TEMP accum;" + "TEMP color;" + "TEMP coord;" + "TEMP step;" + + "MUL step, params, 2.0;" + + "SUB coord, fragment.texcoord[0], step;" + "TEX color.rgba, coord, texture[0], 2D;" + "MOV accum, color;" + + "MOV coord, fragment.texcoord[0];" + "SUB coord.x, coord.x, step.x;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "SUB coord.x, coord.x, step.x;" + "ADD coord.y, coord.y, step.y;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "SUB coord.y, coord.y, step.y;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "ADD coord.y, coord.y, step.y;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "ADD coord.x, coord.x, step.x;" + "SUB coord.y, coord.y, step.y;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "ADD coord.x, coord.x, step.x;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MOV coord, fragment.texcoord[0];" + "ADD coord.x, coord.x, step.x;" + "ADD coord.y, coord.y, step.y;" + "TEX color.rgba, coord, texture[0], 2D;" + "ADD accum, accum, color;" + + "MUL color, accum, 0.11111111;" + "MOV result.color, color;" + "END" + }, + + /*{"invert", + FRAGMENT_SHADER_VARS + FRAGMENT_SHADER_BEGIN + " color.rgb = vec3(1.0, 1.0, 1.0) - color.rgb;\n" + FRAGMENT_SHADER_END + },*/ + {"invert", + "!!ARBfp1.0\n" + "TEMP color;" + "TEX color.rgba, fragment.texcoord[0], texture[0], 2D;" + "ADD color.rgb, 1.0, -color;" + "MOV result.color, color;" + "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 + },*/ + {"gray", + "!!ARBfp1.0\n" + "TEMP color;" + "TEMP grey;" + "TEX color.rgba, fragment.texcoord[0], texture[0], 2D;" + "ADD grey, color.r, color.g;" + "ADD grey, grey, color.b;" + "MUL grey, grey, 0.33333333;" + "MOV color.rgb, grey;" + "MOV result.color, color;" + "END" + }, + +/* {"combined-mirror", + FRAGMENT_SHADER_VARS + FRAGMENT_SHADER_BEGIN + " vec4 colorB = texture2D (tex, vec2(" TEX_COORD ".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 + },*/ + {"combined-mirror", + "!!ARBfp1.0\n" + "TEMP color1;" + "TEMP color2;" + "TEMP coord;" + "MOV coord.x, fragment.texcoord[0].y;" + "MOV coord.y, fragment.texcoord[0].x;" + "TEX color1.rgba, fragment.texcoord[0], texture[0], 2D;" + "TEX color2.rgba, coord, texture[0], 2D;" + "MUL color1, color1, 0.5;" + "MUL color2, color2, 0.5;" + "ADD result.color, color1, color2;" + "END" + }, + +/* {"edge-detect", + FRAGMENT_SHADER_VARS + "float get_avg_rel(sampler2D texB, float dx, float dy)" + "{" + " vec4 colorB = texture2D (texB, " TEX_COORD ".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 + },*/ + + /* Don't really fancy doing this one in assembly :) */ +}; + +static CoglHandle redhand; +static CoglMaterial *material; +static unsigned int timeout_id = 0; +static int shader_no = 0; + +static void +paint_cb (ClutterActor *actor) +{ + int stage_width = clutter_actor_get_width (actor); + int stage_height = clutter_actor_get_height (actor); + int image_width = cogl_texture_get_width (redhand); + int 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); + float param0[4]; + 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); + + program = cogl_create_program (); + cogl_program_attach_shader (program, shader); + cogl_handle_unref (shader); + cogl_program_link (program); + + param0[0] = 1.0f/image_width; /* texel x step delta */ + param0[1] = 1.0f/image_height; /* texel y step delta */ + param0[2] = 0.4; /* brightness */ + param0[3] = -1.9; /* contrast */ + + uniform_no = cogl_program_get_uniform_location (program, "program.local[0]"); + /* Shesh this API is really F'ugly! */ + cogl_program_use (program); + cogl_program_uniform_float (uniform_no, 4, 1, param0); + cogl_program_use (COGL_INVALID_HANDLE); + + cogl_material_set_user_program (material, program); + cogl_handle_unref (program); + + shader_no = new_no; +} + +static gboolean +button_release_cb (ClutterActor *actor, + ClutterEvent *event, + void *data) +{ + int new_no; + + /* Stop the automatic cycling if the user want to manually control + * which shader to display */ + if (timeout_id) + { + g_source_remove (timeout_id); + timeout_id = 0; + } + + 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 FALSE; +} + +static gboolean +key_release_cb (ClutterActor *actor, + ClutterEvent *event, + void *user_data) +{ + if (event->key.keyval == CLUTTER_Q || event->key.keyval == CLUTTER_q) + clutter_main_quit (); + + return FALSE; +} + +static gboolean +timeout_cb (void *user_data) +{ + shader_no++; + if (shader_no > (G_N_ELEMENTS (shaders) - 1)) + shader_no = 0; + + set_shader_num (shader_no); + + return TRUE; +} + +static gboolean +idle_cb (void *data) +{ + clutter_actor_queue_redraw (data); + + return TRUE; +} + +static gboolean +destroy_window_cb (ClutterStage *stage, + ClutterEvent *event, + void *user_data) +{ + clutter_main_quit (); + return TRUE; +} + +G_MODULE_EXPORT int +test_cogl_shader_arbfp_main (int argc, char *argv[]) +{ + ClutterActor *stage; + char *file; + GError *error; + ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; + + clutter_init (&argc, &argv); + + 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, 0, COGL_PIXEL_FORMAT_ANY, + &error); + if (redhand == COGL_INVALID_HANDLE) + 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 = g_timeout_add (1000, timeout_cb, NULL); + + g_idle_add (idle_cb, stage); + + clutter_actor_show_all (stage); + + clutter_main (); + + return EXIT_SUCCESS; +} +