From 72f2fc22adff4fb3e85f9a17644275b1add4a703 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 28 Nov 2008 17:36:37 +0000 Subject: [PATCH] * tests/conform/test-backface-culling.c: New test for backface culling * tests/conform/test-conform-main.c (main): Add /texture/test_backface_culing * tests/conform/Makefile.am (test_conformance_SOURCES): Add test-backface-culling.c --- ChangeLog | 11 ++ tests/conform/Makefile.am | 3 +- tests/conform/test-backface-culling.c | 266 ++++++++++++++++++++++++++ tests/conform/test-conform-main.c | 2 + 4 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 tests/conform/test-backface-culling.c diff --git a/ChangeLog b/ChangeLog index a350dd1ef..f71882749 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-11-28 Neil Roberts + + * tests/conform/test-backface-culling.c: New test for backface + culling + + * tests/conform/test-conform-main.c (main): Add + /texture/test_backface_culing + + * tests/conform/Makefile.am (test_conformance_SOURCES): Add + test-backface-culling.c + 2008-11-28 Neil Roberts * tests/conform/test-mesh-mutability.c: diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index c71242c71..9706b8a03 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -19,7 +19,8 @@ test_conformance_SOURCES = \ test-clutter-rectangle.c \ test-clutter-fixed.c \ test-actor-invariants.c \ - test-paint-opacity.c + test-paint-opacity.c \ + test-backface-culling.c # For convenience, this provides a way to easily run individual unit tests: .PHONY: wrappers diff --git a/tests/conform/test-backface-culling.c b/tests/conform/test-backface-culling.c new file mode 100644 index 000000000..3a18d8916 --- /dev/null +++ b/tests/conform/test-backface-culling.c @@ -0,0 +1,266 @@ + +#include +#include +#include + +#include "test-conform-common.h" + +static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; + +/* Size the texture so that it is just off a power of two to enourage + it so use software tiling when NPOTs aren't available */ +#define TEXTURE_SIZE 33 + +/* Amount of pixels to skip off the top, bottom, left and right of the + texture when reading back the stage */ +#define TEST_INSET 4 + +typedef struct _TestState +{ + guint frame; + CoglHandle texture; +} TestState; + +static gboolean +validate_part (int xnum, int ynum, gboolean shown) +{ + guchar *pixels, *p; + ClutterActor *stage = clutter_stage_get_default (); + gboolean ret = TRUE; + + /* Read the appropriate part but skip out a few pixels around the + edges */ + pixels = clutter_stage_read_pixels (CLUTTER_STAGE (stage), + xnum * TEXTURE_SIZE + TEST_INSET, + ynum * TEXTURE_SIZE + TEST_INSET, + TEXTURE_SIZE - TEST_INSET * 2, + TEXTURE_SIZE - TEST_INSET * 2); + + /* Make sure every pixels is the appropriate color */ + for (p = pixels; + p < pixels + ((TEXTURE_SIZE - TEST_INSET * 2) + * (TEXTURE_SIZE - TEST_INSET * 2)); + p += 4) + { + if (p[0] != (shown ? 255 : 0)) + ret = FALSE; + if (p[1] != 0) + ret = FALSE; + if (p[2] != 0) + ret = FALSE; + } + + g_free (pixels); + + return ret; +} + +static void +validate_result (TestState *state) +{ + /* Front-facing texture */ + g_assert (validate_part (0, 0, TRUE)); + /* Back-facing texture */ + g_assert (validate_part (1, 0, FALSE)); + /* Front-facing texture polygon */ + g_assert (validate_part (2, 0, TRUE)); + /* Back-facing texture polygon */ + g_assert (validate_part (3, 0, FALSE)); + /* Regular rectangle */ + g_assert (validate_part (4, 0, TRUE)); + + /* Backface culling disabled - everything should be shown */ + + /* Front-facing texture */ + g_assert (validate_part (0, 1, TRUE)); + /* Back-facing texture */ + g_assert (validate_part (1, 1, TRUE)); + /* Front-facing texture polygon */ + g_assert (validate_part (2, 1, TRUE)); + /* Back-facing texture polygon */ + g_assert (validate_part (3, 1, TRUE)); + /* Regular rectangle */ + g_assert (validate_part (4, 1, TRUE)); + + /* Comment this out if you want visual feedback of what this test + * paints. + */ + clutter_main_quit (); +} + +static void +on_paint (ClutterActor *actor, TestState *state) +{ + int i; + int frame_num; + + cogl_enable_backface_culling (TRUE); + + cogl_push_matrix (); + + /* Render the scene twice - once with backface culling enabled and + once without. The second time is translated so that it is below + the first */ + for (i = 0; i < 2; i++) + { + CoglFixed x1 = 0, x2, y1 = 0, y2 = COGL_FIXED_FROM_INT (TEXTURE_SIZE); + CoglTextureVertex verts[4]; + + memset (verts, 0, sizeof (verts)); + + /* Set the color to white so that all the textures will be drawn + at their own color */ + cogl_set_source_color4x (COGL_FIXED_1, COGL_FIXED_1, + COGL_FIXED_1, COGL_FIXED_1); + + x2 = x1 + COGL_FIXED_FROM_INT (TEXTURE_SIZE); + + /* Draw a front-facing texture */ + cogl_texture_rectangle (state->texture, + x1, y1, x2, y2, + 0, 0, COGL_FIXED_1, COGL_FIXED_1); + + x1 = x2; + x2 = x1 + COGL_FIXED_FROM_INT (TEXTURE_SIZE); + + /* Draw a back-facing texture */ + cogl_texture_rectangle (state->texture, + x2, y1, x1, y2, + 0, 0, COGL_FIXED_1, COGL_FIXED_1); + + x1 = x2; + x2 = x1 + COGL_FIXED_FROM_INT (TEXTURE_SIZE); + + /* Draw a front-facing texture polygon */ + verts[0].x = x1; verts[0].y = y2; + verts[1].x = x2; verts[1].y = y2; + verts[2].x = x2; verts[2].y = y1; + verts[3].x = x1; verts[3].y = y1; + verts[0].tx = 0; verts[0].ty = 0; + verts[1].tx = COGL_FIXED_1; verts[1].ty = 0; + verts[2].tx = COGL_FIXED_1; verts[2].ty = COGL_FIXED_1; + verts[3].tx = 0; verts[3].ty = COGL_FIXED_1; + cogl_texture_polygon (state->texture, 4, + verts, FALSE); + + x1 = x2; + x2 = x1 + COGL_FIXED_FROM_INT (TEXTURE_SIZE); + + /* Draw a back-facing texture polygon */ + verts[0].x = x1; verts[0].y = y1; + verts[1].x = x2; verts[1].y = y1; + verts[2].x = x2; verts[2].y = y2; + verts[3].x = x1; verts[3].y = y2; + verts[0].tx = 0; verts[0].ty = 0; + verts[1].tx = COGL_FIXED_1; verts[1].ty = 0; + verts[2].tx = COGL_FIXED_1; verts[2].ty = COGL_FIXED_1; + verts[3].tx = 0; verts[3].ty = COGL_FIXED_1; + cogl_texture_polygon (state->texture, 4, + verts, FALSE); + + x1 = x2; + x2 = x1 + COGL_FIXED_FROM_INT (TEXTURE_SIZE); + + /* Draw a regular rectangle (this should always show) */ + cogl_set_source_color4x (COGL_FIXED_1, 0, 0, COGL_FIXED_1); + cogl_rectangle (COGL_FIXED_TO_INT (x1), COGL_FIXED_TO_INT (y1), + COGL_FIXED_TO_INT (x2 - x1), COGL_FIXED_TO_INT (y2 - y1)); + + /* The second time round draw beneath the first with backface + culling disabled */ + cogl_translate (0, TEXTURE_SIZE, 0); + cogl_enable_backface_culling (FALSE); + } + + cogl_pop_matrix (); + + /* XXX: Experiments have shown that for some buggy drivers, when using + * glReadPixels there is some kind of race, so we delay our test for a + * few frames and a few seconds: + */ + /* Need to increment frame first because clutter_stage_read_pixels + fires a redraw */ + frame_num = state->frame++; + if (frame_num == 2) + validate_result (state); + else if (frame_num < 2) + g_usleep (G_USEC_PER_SEC); +} + +static gboolean +queue_redraw (gpointer stage) +{ + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); + + return TRUE; +} + +static CoglHandle +make_texture (void) +{ + guchar *tex_data, *p; + CoglHandle tex; + + tex_data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4); + + for (p = tex_data + TEXTURE_SIZE * TEXTURE_SIZE * 4; p > tex_data;) + { + *(--p) = 255; + *(--p) = 0; + *(--p) = 0; + *(--p) = 255; + } + + tex = cogl_texture_new_from_data (TEXTURE_SIZE, + TEXTURE_SIZE, + 8, + FALSE, + COGL_PIXEL_FORMAT_RGBA_8888, + COGL_PIXEL_FORMAT_ANY, + TEXTURE_SIZE * 4, + tex_data); + + g_free (tex_data); + + return tex; +} + +void +test_backface_culling (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + TestState state; + ClutterActor *stage; + ClutterActor *group; + guint idle_source; + + state.frame = 0; + + state.texture = make_texture (); + + stage = clutter_stage_get_default (); + + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + + group = clutter_group_new (); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); + + /* We force continuous redrawing of the stage, since we need to skip + * the first few frames, and we wont be doing anything else that + * will trigger redrawing. */ + idle_source = g_idle_add (queue_redraw, stage); + + g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); + + clutter_actor_show_all (stage); + + clutter_main (); + + g_source_remove (idle_source); + + cogl_texture_unref (state.texture); + + if (g_test_verbose ()) + g_print ("OK\n"); +} + diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index b70ab1caf..1f6e2c811 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -103,5 +103,7 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/opacity", test_rectangle_opacity); TEST_CONFORM_SIMPLE ("/opacity", test_paint_opacity); + TEST_CONFORM_SIMPLE ("/texture", test_backface_culling); + return g_test_run (); }