summaryrefslogtreecommitdiff
path: root/tests/conform/test-backface-culling.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/conform/test-backface-culling.c')
-rw-r--r--tests/conform/test-backface-culling.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/tests/conform/test-backface-culling.c b/tests/conform/test-backface-culling.c
new file mode 100644
index 00000000..d4f3e0d9
--- /dev/null
+++ b/tests/conform/test-backface-culling.c
@@ -0,0 +1,339 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+#ifdef CLUTTER_COGL_HAS_GL
+
+/* 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 257
+
+#else /* CLUTTER_COGL_HAS_GL */
+
+/* We can't use the funny-sized texture on GL ES because it will break
+ cogl_texture_polygon. However there is only one code path for
+ rendering quads so there is no need */
+#define TEXTURE_SIZE 32
+
+#endif /* CLUTTER_COGL_HAS_GL */
+
+/* Amount of pixels to skip off the top, bottom, left and right of the
+ texture when reading back the stage */
+#define TEST_INSET 4
+
+/* Size to actually render the texture at */
+#define TEXTURE_RENDER_SIZE 32
+
+typedef struct _TestState
+{
+ CoglHandle texture;
+ CoglHandle offscreen;
+ CoglHandle offscreen_tex;
+} TestState;
+
+static gboolean
+validate_part (int xnum, int ynum, gboolean shown)
+{
+ guchar *pixels, *p;
+ gboolean ret = TRUE;
+
+ pixels = g_malloc0 ((TEXTURE_RENDER_SIZE - TEST_INSET * 2)
+ * (TEXTURE_RENDER_SIZE - TEST_INSET * 2) * 4);
+
+ /* Read the appropriate part but skip out a few pixels around the
+ edges */
+ cogl_read_pixels (xnum * TEXTURE_RENDER_SIZE + TEST_INSET,
+ ynum * TEXTURE_RENDER_SIZE + TEST_INSET,
+ TEXTURE_RENDER_SIZE - TEST_INSET * 2,
+ TEXTURE_RENDER_SIZE - TEST_INSET * 2,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixels);
+
+ /* Make sure every pixels is the appropriate color */
+ for (p = pixels;
+ p < pixels + ((TEXTURE_RENDER_SIZE - TEST_INSET * 2)
+ * (TEXTURE_RENDER_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
+do_test_backface_culling (TestState *state)
+{
+ int i;
+ CoglHandle material = cogl_material_new ();
+
+ cogl_material_set_layer_filters (material, 0,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+
+ cogl_set_backface_culling_enabled (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++)
+ {
+ float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE);
+ CoglTextureVertex verts[4];
+
+ cogl_set_source (material);
+
+ memset (verts, 0, sizeof (verts));
+
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a front-facing texture */
+ cogl_material_set_layer (material, 0, state->texture);
+ cogl_rectangle (x1, y1, x2, y2);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a front-facing texture with flipped texcoords */
+ cogl_material_set_layer (material, 0, state->texture);
+ cogl_rectangle_with_texture_coords (x1, y1, x2, y2,
+ 1.0, 0.0, 0.0, 1.0);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a back-facing texture */
+ cogl_material_set_layer (material, 0, state->texture);
+ cogl_rectangle (x2, y1, x1, y2);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_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 = 1.0; verts[1].ty = 0;
+ verts[2].tx = 1.0; verts[2].ty = 1.0;
+ verts[3].tx = 0; verts[3].ty = 1.0;
+ cogl_material_set_layer (material, 0, state->texture);
+ cogl_polygon (verts, 4, FALSE);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_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 = 1.0; verts[1].ty = 0;
+ verts[2].tx = 1.0; verts[2].ty = 1.0;
+ verts[3].tx = 0; verts[3].ty = 1.0;
+ cogl_material_set_layer (material, 0, state->texture);
+ cogl_polygon (verts, 4, FALSE);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a regular rectangle (this should always show) */
+ cogl_set_source_color4f (1.0, 0, 0, 1.0);
+ cogl_rectangle (x1, y1, x2, y2);
+
+ /* The second time round draw beneath the first with backface
+ culling disabled */
+ cogl_translate (0, TEXTURE_RENDER_SIZE, 0);
+ cogl_set_backface_culling_enabled (FALSE);
+ }
+
+ cogl_handle_unref (material);
+
+ cogl_pop_matrix ();
+
+ /* Front-facing texture */
+ g_assert (validate_part (0, 0, TRUE));
+ /* Front-facing texture with flipped tex coords */
+ g_assert (validate_part (1, 0, TRUE));
+ /* Back-facing texture */
+ g_assert (validate_part (2, 0, FALSE));
+ /* Front-facing texture polygon */
+ g_assert (validate_part (3, 0, TRUE));
+ /* Back-facing texture polygon */
+ g_assert (validate_part (4, 0, FALSE));
+ /* Regular rectangle */
+ g_assert (validate_part (5, 0, TRUE));
+
+ /* Backface culling disabled - everything should be shown */
+
+ /* Front-facing texture */
+ g_assert (validate_part (0, 1, TRUE));
+ /* Front-facing texture with flipped tex coords */
+ g_assert (validate_part (1, 1, TRUE));
+ /* Back-facing texture */
+ g_assert (validate_part (2, 1, TRUE));
+ /* Front-facing texture polygon */
+ g_assert (validate_part (3, 1, TRUE));
+ /* Back-facing texture polygon */
+ g_assert (validate_part (4, 1, TRUE));
+ /* Regular rectangle */
+ g_assert (validate_part (5, 1, TRUE));
+
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ CoglColor clr;
+ float stage_viewport[4];
+ CoglMatrix stage_projection;
+ CoglMatrix stage_modelview;
+
+ cogl_color_init_from_4ub (&clr, 0x00, 0x00, 0x00, 0xff);
+
+ do_test_backface_culling (state);
+
+ /* Since we are going to repeat the test rendering offscreen we clear the
+ * stage, just to minimize the chance of a some other bug causing us
+ * mistakenly reading back the results from the stage and giving a false
+ * posistive. */
+ cogl_clear (&clr, COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_STENCIL);
+
+ /*
+ * Now repeat the test but rendered to an offscreen framebuffer...
+ */
+
+ cogl_get_viewport (stage_viewport);
+ cogl_get_projection_matrix (&stage_projection);
+ cogl_get_modelview_matrix (&stage_modelview);
+
+ cogl_push_framebuffer (state->offscreen);
+
+ cogl_clear (&clr, COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_STENCIL);
+
+ cogl_set_viewport (stage_viewport[0],
+ stage_viewport[1],
+ stage_viewport[2],
+ stage_viewport[3]);
+ cogl_set_projection_matrix (&stage_projection);
+ cogl_set_modelview_matrix (&stage_modelview);
+
+ do_test_backface_culling (state);
+
+ cogl_pop_framebuffer ();
+
+ /* Incase we want feedback of what was drawn offscreen we draw it
+ * to the stage... */
+ cogl_set_source_texture (state->offscreen_tex);
+ cogl_rectangle (0, 0, stage_viewport[2], stage_viewport[3]);
+
+ /* Comment this out if you want visual feedback of what this test
+ * paints.
+ */
+ clutter_main_quit ();
+}
+
+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,
+ COGL_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ COGL_PIXEL_FORMAT_ANY,
+ TEXTURE_SIZE * 4,
+ tex_data);
+
+ g_free (tex_data);
+
+ return tex;
+}
+
+void
+test_cogl_backface_culling (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ CoglHandle tex;
+ ClutterActor *stage;
+ float stage_width;
+ float stage_height;
+ const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+ ClutterActor *group;
+ unsigned int idle_source;
+
+ stage = clutter_stage_get_default ();
+ clutter_actor_get_size (stage, &stage_width, &stage_height);
+
+ state.offscreen = COGL_INVALID_HANDLE;
+
+ state.texture = make_texture ();
+
+ tex = cogl_texture_new_with_size (stage_width, stage_height,
+ COGL_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_ANY); /* internal fmt */
+ state.offscreen = cogl_offscreen_new_to_texture (tex);
+ state.offscreen_tex = tex;
+
+ 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_handle_unref (state.offscreen);
+ cogl_handle_unref (state.offscreen_tex);
+ cogl_handle_unref (state.texture);
+
+ if (g_test_verbose ())
+ g_print ("OK\n");
+}
+