"Initial commit to Gerrit"
[profile/ivi/cogl.git] / tests / conform / test-sub-texture.c
1 #include <cogl/cogl.h>
2 #include <string.h>
3
4 #include "test-utils.h"
5
6 #define SOURCE_SIZE        32
7 #define SOURCE_DIVISIONS_X 2
8 #define SOURCE_DIVISIONS_Y 2
9 #define DIVISION_WIDTH     (SOURCE_SIZE / SOURCE_DIVISIONS_X)
10 #define DIVISION_HEIGHT    (SOURCE_SIZE / SOURCE_DIVISIONS_Y)
11
12 #define TEST_INSET         1
13
14 static const guint32
15 corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] =
16   {
17     0xff0000ff, /* red top left */
18     0x00ff00ff, /* green top right */
19     0x0000ffff, /* blue bottom left */
20     0xff00ffff  /* purple bottom right */
21   };
22
23 typedef struct _TestState
24 {
25   CoglTexture2D *tex;
26 } TestState;
27
28 static CoglTexture2D *
29 create_source (TestState *state)
30 {
31   int dx, dy;
32   guint8 *data = g_malloc (SOURCE_SIZE * SOURCE_SIZE * 4);
33   CoglTexture2D *tex;
34   GError *error = NULL;
35
36   /* Create a texture with a different coloured rectangle at each
37      corner */
38   for (dy = 0; dy < SOURCE_DIVISIONS_Y; dy++)
39     for (dx = 0; dx < SOURCE_DIVISIONS_X; dx++)
40       {
41         guint8 *p = (data + dy * DIVISION_HEIGHT * SOURCE_SIZE * 4 +
42                      dx * DIVISION_WIDTH * 4);
43         int x, y;
44
45         for (y = 0; y < DIVISION_HEIGHT; y++)
46           {
47             for (x = 0; x < DIVISION_WIDTH; x++)
48               {
49                 guint32 color = GUINT32_FROM_BE (corner_colors[dx + dy * SOURCE_DIVISIONS_X]);
50                 memcpy (p, &color, 4);
51                 p += 4;
52               }
53
54             p += SOURCE_SIZE * 4 - DIVISION_WIDTH * 4;
55           }
56       }
57
58   tex = cogl_texture_2d_new_from_data (ctx,
59                                        SOURCE_SIZE, SOURCE_SIZE,
60                                        COGL_PIXEL_FORMAT_RGBA_8888,
61                                        COGL_PIXEL_FORMAT_ANY,
62                                        SOURCE_SIZE * 4,
63                                        data,
64                                        &error);
65   g_assert_no_error (error);
66   return tex;
67 }
68
69 static CoglTexture2D *
70 create_test_texture (TestState *state)
71 {
72   CoglTexture2D *tex;
73   guint8 *data = g_malloc (256 * 256 * 4), *p = data;
74   int x, y;
75   GError *error = NULL;
76
77   /* Create a texture that is 256x256 where the red component ranges
78      from 0->255 along the x axis and the green component ranges from
79      0->255 along the y axis. The blue and alpha components are all
80      255 */
81   for (y = 0; y < 256; y++)
82     for (x = 0; x < 256; x++)
83       {
84         *(p++) = x;
85         *(p++) = y;
86         *(p++) = 255;
87         *(p++) = 255;
88       }
89
90   tex = cogl_texture_2d_new_from_data (ctx,
91                                        256, 256,
92                                        COGL_PIXEL_FORMAT_RGBA_8888_PRE,
93                                        COGL_PIXEL_FORMAT_ANY,
94                                        256 * 4,
95                                        data,
96                                        &error);
97   g_assert_no_error (error);
98
99   g_free (data);
100
101   return tex;
102 }
103
104 static void
105 paint (TestState *state)
106 {
107   CoglTexture2D *full_texture;
108   CoglSubTexture *sub_texture, *sub_sub_texture;
109   CoglPipeline *pipeline = cogl_pipeline_new (ctx);
110
111   /* Create a sub texture of the bottom right quarter of the texture */
112   sub_texture = cogl_sub_texture_new (ctx,
113                                       COGL_TEXTURE (state->tex),
114                                       DIVISION_WIDTH,
115                                       DIVISION_HEIGHT,
116                                       DIVISION_WIDTH,
117                                       DIVISION_HEIGHT);
118
119   /* Paint it */
120   cogl_pipeline_set_layer_texture (pipeline, 0, COGL_TEXTURE (sub_texture));
121   cogl_object_unref (sub_texture);
122   cogl_framebuffer_draw_rectangle (fb, pipeline,
123                                    0.0f, 0.0f, DIVISION_WIDTH, DIVISION_HEIGHT);
124
125
126   /* Repeat a sub texture of the top half of the full texture. This is
127      documented to be undefined so it doesn't technically have to work
128      but it will with the current implementation */
129   sub_texture = cogl_sub_texture_new (ctx,
130                                       COGL_TEXTURE (state->tex),
131                                       0, 0,
132                                       SOURCE_SIZE,
133                                       DIVISION_HEIGHT);
134   cogl_pipeline_set_layer_texture (pipeline, 0, COGL_TEXTURE (sub_texture));
135   cogl_object_unref (sub_texture);
136   cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
137                                             0.0f,
138                                             SOURCE_SIZE,
139                                             SOURCE_SIZE * 2.0f,
140                                             SOURCE_SIZE * 1.5f,
141                                             0.0f, 0.0f,
142                                             2.0f, 1.0f);
143
144   /* Create a sub texture of a sub texture */
145   full_texture = create_test_texture (state);
146   sub_texture = cogl_sub_texture_new (ctx,
147                                       COGL_TEXTURE (full_texture),
148                                       20, 10, 30, 20);
149   cogl_object_unref (full_texture);
150   sub_sub_texture = cogl_sub_texture_new (ctx,
151                                           COGL_TEXTURE (sub_texture),
152                                           20, 10, 10, 10);
153   cogl_object_unref (sub_texture);
154   cogl_pipeline_set_layer_texture (pipeline, 0, COGL_TEXTURE (sub_sub_texture));
155   cogl_object_unref (sub_sub_texture);
156   cogl_framebuffer_draw_rectangle (fb, pipeline,
157                                    0.0f, SOURCE_SIZE * 2.0f,
158                                    10.0f, SOURCE_SIZE * 2.0f + 10.0f);
159
160   cogl_object_unref (pipeline);
161 }
162
163 static void
164 validate_part (int xpos, int ypos,
165                int width, int height,
166                guint32 color)
167 {
168   test_utils_check_region (fb,
169                            xpos + TEST_INSET,
170                            ypos + TEST_INSET,
171                            width - TEST_INSET - 2,
172                            height - TEST_INSET - 2,
173                            color);
174 }
175
176 static guint8 *
177 create_update_data (void)
178 {
179   guint8 *data = g_malloc (256 * 256 * 4), *p = data;
180   int x, y;
181
182   /* Create some image data that is 256x256 where the blue component
183      ranges from 0->255 along the x axis and the alpha component
184      ranges from 0->255 along the y axis. The red and green components
185      are all zero */
186   for (y = 0; y < 256; y++)
187     for (x = 0; x < 256; x++)
188       {
189         *(p++) = 0;
190         *(p++) = 0;
191         *(p++) = x;
192         *(p++) = y;
193       }
194
195   return data;
196 }
197
198 static void
199 validate_result (TestState *state)
200 {
201   int i, division_num, x, y;
202   CoglTexture2D *test_tex;
203   CoglSubTexture *sub_texture;
204   guint8 *texture_data, *p;
205   int tex_width, tex_height;
206
207   /* Sub texture of the bottom right corner of the texture */
208   validate_part (0, 0, DIVISION_WIDTH, DIVISION_HEIGHT,
209                  corner_colors[
210                  (SOURCE_DIVISIONS_Y - 1) * SOURCE_DIVISIONS_X +
211                  SOURCE_DIVISIONS_X - 1]);
212
213   /* Sub texture of the top half repeated horizontally */
214   for (i = 0; i < 2; i++)
215     for (division_num = 0; division_num < SOURCE_DIVISIONS_X; division_num++)
216       validate_part (i * SOURCE_SIZE + division_num * DIVISION_WIDTH,
217                      SOURCE_SIZE,
218                      DIVISION_WIDTH, DIVISION_HEIGHT,
219                      corner_colors[division_num]);
220
221   /* Sub sub texture */
222   p = texture_data = g_malloc (10 * 10 * 4);
223   cogl_flush ();
224   cogl_framebuffer_read_pixels (fb,
225                                 0, SOURCE_SIZE * 2, 10, 10,
226                                 COGL_PIXEL_FORMAT_RGBA_8888,
227                                 p);
228   for (y = 0; y < 10; y++)
229     for (x = 0; x < 10; x++)
230       {
231         g_assert (*(p++) == x + 40);
232         g_assert (*(p++) == y + 20);
233         p += 2;
234       }
235   g_free (texture_data);
236
237   /* Try reading back the texture data */
238   sub_texture = cogl_sub_texture_new (ctx,
239                                       COGL_TEXTURE (state->tex),
240                                       SOURCE_SIZE / 4,
241                                       SOURCE_SIZE / 4,
242                                       SOURCE_SIZE / 2,
243                                       SOURCE_SIZE / 2);
244   tex_width = cogl_texture_get_width (COGL_TEXTURE (sub_texture));
245   tex_height = cogl_texture_get_height (COGL_TEXTURE (sub_texture));
246   p = texture_data = g_malloc (tex_width * tex_height * 4);
247   cogl_texture_get_data (COGL_TEXTURE (sub_texture),
248                          COGL_PIXEL_FORMAT_RGBA_8888,
249                          tex_width * 4,
250                          texture_data);
251   for (y = 0; y < tex_height; y++)
252     for (x = 0; x < tex_width; x++)
253       {
254         int div_x = ((x * SOURCE_SIZE / 2 / tex_width + SOURCE_SIZE / 4) /
255                      DIVISION_WIDTH);
256         int div_y = ((y * SOURCE_SIZE / 2 / tex_height + SOURCE_SIZE / 4) /
257                      DIVISION_HEIGHT);
258         guint32 reference = corner_colors[div_x + div_y * SOURCE_DIVISIONS_X] >> 8;
259         guint32 color = GUINT32_FROM_BE (*((guint32 *)p)) >> 8;
260         g_assert (color == reference);
261         p += 4;
262       }
263   g_free (texture_data);
264   cogl_object_unref (sub_texture);
265
266   /* Create a 256x256 test texture */
267   test_tex = create_test_texture (state);
268   /* Create a sub texture the views the center half of the texture */
269   sub_texture = cogl_sub_texture_new (ctx,
270                                       COGL_TEXTURE (test_tex),
271                                       64, 64, 128, 128);
272   /* Update the center half of the sub texture */
273   texture_data = create_update_data ();
274   cogl_texture_set_region (COGL_TEXTURE (sub_texture),
275                            0, 0, 32, 32, 64, 64, 256, 256,
276                            COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4,
277                            texture_data);
278   g_free (texture_data);
279   cogl_object_unref (sub_texture);
280   /* Get the texture data */
281   p = texture_data = g_malloc (256 * 256 * 4);
282   cogl_texture_get_data (COGL_TEXTURE (test_tex),
283                          COGL_PIXEL_FORMAT_RGBA_8888_PRE,
284                          256 * 4, texture_data);
285
286   /* Verify the texture data */
287   for (y = 0; y < 256; y++)
288     for (x = 0; x < 256; x++)
289       {
290         /* If we're in the center quarter */
291         if (x >= 96 && x < 160 && y >= 96 && y < 160)
292           {
293             g_assert ((*p++) == 0);
294             g_assert ((*p++) == 0);
295             g_assert ((*p++) == x - 96);
296             g_assert ((*p++) == y - 96);
297           }
298         else
299           {
300             g_assert ((*p++) == x);
301             g_assert ((*p++) == y);
302             g_assert ((*p++) == 255);
303             g_assert ((*p++) == 255);
304           }
305       }
306   g_free (texture_data);
307   cogl_object_unref (test_tex);
308 }
309
310 void
311 test_sub_texture (void)
312 {
313   TestState state;
314
315   state.tex = create_source (&state);
316
317   cogl_framebuffer_orthographic (fb,
318                                  0, 0,
319                                  cogl_framebuffer_get_width (fb),
320                                  cogl_framebuffer_get_height (fb),
321                                  -1,
322                                  100);
323
324   paint (&state);
325   validate_result (&state);
326
327   cogl_object_unref (state.tex);
328
329   if (cogl_test_verbose ())
330     g_print ("OK\n");
331 }
332