#include #include #include "test-utils.h" #define SOURCE_SIZE 32 #define SOURCE_DIVISIONS_X 2 #define SOURCE_DIVISIONS_Y 2 #define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X) #define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y) #define TEST_INSET 1 static const guint32 corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] = { 0xff0000ff, /* red top left */ 0x00ff00ff, /* green top right */ 0x0000ffff, /* blue bottom left */ 0xff00ffff /* purple bottom right */ }; typedef struct _TestState { CoglContext *ctx; CoglTexture2D *tex; } TestState; static CoglTexture2D * create_source (TestState *state) { int dx, dy; guint8 *data = g_malloc (SOURCE_SIZE * SOURCE_SIZE * 4); CoglTexture2D *tex; GError *error = NULL; /* Create a texture with a different coloured rectangle at each corner */ for (dy = 0; dy < SOURCE_DIVISIONS_Y; dy++) for (dx = 0; dx < SOURCE_DIVISIONS_X; dx++) { guint8 *p = (data + dy * DIVISION_HEIGHT * SOURCE_SIZE * 4 + dx * DIVISION_WIDTH * 4); int x, y; for (y = 0; y < DIVISION_HEIGHT; y++) { for (x = 0; x < DIVISION_WIDTH; x++) { guint32 color = GUINT32_FROM_BE (corner_colors[dx + dy * SOURCE_DIVISIONS_X]); memcpy (p, &color, 4); p += 4; } p += SOURCE_SIZE * 4 - DIVISION_WIDTH * 4; } } tex = cogl_texture_2d_new_from_data (state->ctx, SOURCE_SIZE, SOURCE_SIZE, COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_ANY, SOURCE_SIZE * 4, data, &error); g_assert_no_error (error); return tex; } static CoglTexture2D * create_test_texture (TestState *state) { CoglTexture2D *tex; guint8 *data = g_malloc (256 * 256 * 4), *p = data; int x, y; GError *error = NULL; /* Create a texture that is 256x256 where the red component ranges from 0->255 along the x axis and the green component ranges from 0->255 along the y axis. The blue and alpha components are all 255 */ for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { *(p++) = x; *(p++) = y; *(p++) = 255; *(p++) = 255; } tex = cogl_texture_2d_new_from_data (state->ctx, 256, 256, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_ANY, 256 * 4, data, &error); g_assert_no_error (error); g_free (data); return tex; } static void paint (TestState *state) { CoglTexture2D *full_texture; CoglSubTexture *sub_texture, *sub_sub_texture; /* Create a sub texture of the bottom right quarter of the texture */ sub_texture = cogl_sub_texture_new (state->ctx, COGL_TEXTURE (state->tex), DIVISION_WIDTH, DIVISION_HEIGHT, DIVISION_WIDTH, DIVISION_HEIGHT); /* Paint it */ cogl_set_source_texture (COGL_TEXTURE (sub_texture)); cogl_rectangle (0.0f, 0.0f, DIVISION_WIDTH, DIVISION_HEIGHT); cogl_object_unref (sub_texture); /* Repeat a sub texture of the top half of the full texture. This is documented to be undefined so it doesn't technically have to work but it will with the current implementation */ sub_texture = cogl_sub_texture_new (state->ctx, COGL_TEXTURE (state->tex), 0, 0, SOURCE_SIZE, DIVISION_HEIGHT); cogl_set_source_texture (COGL_TEXTURE (sub_texture)); cogl_rectangle_with_texture_coords (0.0f, SOURCE_SIZE, SOURCE_SIZE * 2.0f, SOURCE_SIZE * 1.5f, 0.0f, 0.0f, 2.0f, 1.0f); cogl_object_unref (sub_texture); /* Create a sub texture of a sub texture */ full_texture = create_test_texture (state); sub_texture = cogl_sub_texture_new (state->ctx, COGL_TEXTURE (full_texture), 20, 10, 30, 20); sub_sub_texture = cogl_sub_texture_new (state->ctx, COGL_TEXTURE (sub_texture), 20, 10, 10, 10); cogl_set_source_texture (COGL_TEXTURE (sub_sub_texture)); cogl_rectangle (0.0f, SOURCE_SIZE * 2.0f, 10.0f, SOURCE_SIZE * 2.0f + 10.0f); cogl_object_unref (sub_sub_texture); cogl_object_unref (sub_texture); cogl_object_unref (full_texture); } static void validate_part (int xpos, int ypos, int width, int height, guint32 color) { test_utils_check_region (xpos + TEST_INSET, ypos + TEST_INSET, width - TEST_INSET - 2, height - TEST_INSET - 2, color); } static guint8 * create_update_data (void) { guint8 *data = g_malloc (256 * 256 * 4), *p = data; int x, y; /* Create some image data that is 256x256 where the blue component ranges from 0->255 along the x axis and the alpha component ranges from 0->255 along the y axis. The red and green components are all zero */ for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { *(p++) = 0; *(p++) = 0; *(p++) = x; *(p++) = y; } return data; } static void validate_result (TestState *state) { int i, division_num, x, y; CoglTexture2D *test_tex; CoglSubTexture *sub_texture; guint8 *texture_data, *p; int tex_width, tex_height; /* Sub texture of the bottom right corner of the texture */ validate_part (0, 0, DIVISION_WIDTH, DIVISION_HEIGHT, corner_colors[ (SOURCE_DIVISIONS_Y - 1) * SOURCE_DIVISIONS_X + SOURCE_DIVISIONS_X - 1]); /* Sub texture of the top half repeated horizontally */ for (i = 0; i < 2; i++) for (division_num = 0; division_num < SOURCE_DIVISIONS_X; division_num++) validate_part (i * SOURCE_SIZE + division_num * DIVISION_WIDTH, SOURCE_SIZE, DIVISION_WIDTH, DIVISION_HEIGHT, corner_colors[division_num]); /* Sub sub texture */ p = texture_data = g_malloc (10 * 10 * 4); cogl_read_pixels (0, SOURCE_SIZE * 2, 10, 10, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888, p); for (y = 0; y < 10; y++) for (x = 0; x < 10; x++) { g_assert (*(p++) == x + 40); g_assert (*(p++) == y + 20); p += 2; } g_free (texture_data); /* Try reading back the texture data */ sub_texture = cogl_sub_texture_new (state->ctx, COGL_TEXTURE (state->tex), SOURCE_SIZE / 4, SOURCE_SIZE / 4, SOURCE_SIZE / 2, SOURCE_SIZE / 2); tex_width = cogl_texture_get_width (COGL_TEXTURE (sub_texture)); tex_height = cogl_texture_get_height (COGL_TEXTURE (sub_texture)); p = texture_data = g_malloc (tex_width * tex_height * 4); cogl_texture_get_data (COGL_TEXTURE (sub_texture), COGL_PIXEL_FORMAT_RGBA_8888, tex_width * 4, texture_data); for (y = 0; y < tex_height; y++) for (x = 0; x < tex_width; x++) { int div_x = ((x * SOURCE_SIZE / 2 / tex_width + SOURCE_SIZE / 4) / DIVISION_WIDTH); int div_y = ((y * SOURCE_SIZE / 2 / tex_height + SOURCE_SIZE / 4) / DIVISION_HEIGHT); guint32 reference = corner_colors[div_x + div_y * SOURCE_DIVISIONS_X] >> 8; guint32 color = GUINT32_FROM_BE (*((guint32 *)p)) >> 8; g_assert (color == reference); p += 4; } g_free (texture_data); cogl_object_unref (sub_texture); /* Create a 256x256 test texture */ test_tex = create_test_texture (state); /* Create a sub texture the views the center half of the texture */ sub_texture = cogl_sub_texture_new (state->ctx, COGL_TEXTURE (test_tex), 64, 64, 128, 128); /* Update the center half of the sub texture */ texture_data = create_update_data (); cogl_texture_set_region (COGL_TEXTURE (sub_texture), 0, 0, 32, 32, 64, 64, 256, 256, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4, texture_data); g_free (texture_data); cogl_object_unref (sub_texture); /* Get the texture data */ p = texture_data = g_malloc (256 * 256 * 4); cogl_texture_get_data (COGL_TEXTURE (test_tex), COGL_PIXEL_FORMAT_RGBA_8888, 256 * 4, texture_data); /* Verify the texture data */ for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { /* If we're in the center quarter */ if (x >= 96 && x < 160 && y >= 96 && y < 160) { g_assert ((*p++) == 0); g_assert ((*p++) == 0); g_assert ((*p++) == x - 96); g_assert ((*p++) == y - 96); } else { g_assert ((*p++) == x); g_assert ((*p++) == y); g_assert ((*p++) == 255); g_assert ((*p++) == 255); } } g_free (texture_data); cogl_object_unref (test_tex); } void test_cogl_sub_texture (TestUtilsGTestFixture *fixture, void *data) { TestUtilsSharedState *shared_state = data; TestState state; state.ctx = shared_state->ctx; state.tex = create_source (&state); cogl_ortho (0, cogl_framebuffer_get_width (shared_state->fb), /* left, right */ cogl_framebuffer_get_height (shared_state->fb), 0, /* bottom, top */ -1, 100 /* z near, far */); paint (&state); validate_result (&state); cogl_object_unref (state.tex); if (g_test_verbose ()) g_print ("OK\n"); }