"Initial commit to Gerrit"
[profile/ivi/cogl.git] / tests / conform / test-texture-3d.c
1 #include <cogl/cogl2-experimental.h>
2 #include <string.h>
3
4 #include "test-utils.h"
5
6 #define TEX_WIDTH        4
7 #define TEX_HEIGHT       8
8 #define TEX_DEPTH        16
9 /* Leave four bytes of padding between each row */
10 #define TEX_ROWSTRIDE    (TEX_WIDTH * 4 + 4)
11 /* Leave four rows of padding between each image */
12 #define TEX_IMAGE_STRIDE ((TEX_HEIGHT + 4) * TEX_ROWSTRIDE)
13
14 typedef struct _TestState
15 {
16   int fb_width;
17   int fb_height;
18 } TestState;
19
20 static CoglTexture3D *
21 create_texture_3d (CoglContext *context)
22 {
23   int x, y, z;
24   guint8 *data = g_malloc (TEX_IMAGE_STRIDE * TEX_DEPTH);
25   guint8 *p = data;
26   CoglTexture3D *tex;
27   GError *error = NULL;
28
29   for (z = 0; z < TEX_DEPTH; z++)
30     {
31       for (y = 0; y < TEX_HEIGHT; y++)
32         {
33           for (x = 0; x < TEX_WIDTH; x++)
34             {
35               /* Set red, green, blue to values based on x, y, z */
36               *(p++) = 255 - x * 8;
37               *(p++) = y * 8;
38               *(p++) = 255 - z * 8;
39               /* Fully opaque */
40               *(p++) = 0xff;
41             }
42
43           /* Set the padding between rows to 0xde */
44           memset (p, 0xde, TEX_ROWSTRIDE - (TEX_WIDTH * 4));
45           p += TEX_ROWSTRIDE - (TEX_WIDTH * 4);
46         }
47       /* Set the padding between images to 0xad */
48       memset (p, 0xba, TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE));
49       p += TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE);
50     }
51
52   tex = cogl_texture_3d_new_from_data (context,
53                                        TEX_WIDTH, TEX_HEIGHT, TEX_DEPTH,
54                                        COGL_PIXEL_FORMAT_RGBA_8888,
55                                        COGL_PIXEL_FORMAT_ANY,
56                                        TEX_ROWSTRIDE,
57                                        TEX_IMAGE_STRIDE,
58                                        data,
59                                        &error);
60
61   if (tex == NULL)
62     {
63       g_assert (error != NULL);
64       g_warning ("Failed to create 3D texture: %s", error->message);
65       g_assert_not_reached ();
66     }
67
68   g_free (data);
69
70   return tex;
71 }
72
73 static void
74 draw_frame (TestState *state)
75 {
76   CoglTexture *tex = COGL_TEXTURE (create_texture_3d (ctx));
77   CoglPipeline *pipeline = cogl_pipeline_new (ctx);
78   typedef struct { float x, y, s, t, r; } Vert;
79   CoglPrimitive *primitive;
80   CoglAttributeBuffer *attribute_buffer;
81   CoglAttribute *attributes[2];
82   Vert *verts, *v;
83   int i;
84
85   cogl_pipeline_set_layer_texture (pipeline, 0, tex);
86   cogl_object_unref (tex);
87   cogl_pipeline_set_layer_filters (pipeline, 0,
88                                    COGL_PIPELINE_FILTER_NEAREST,
89                                    COGL_PIPELINE_FILTER_NEAREST);
90
91   /* Render the texture repeated horizontally twice using a regular
92      cogl rectangle. This should end up with the r texture coordinates
93      as zero */
94   cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
95                                             0.0f, 0.0f, TEX_WIDTH * 2, TEX_HEIGHT,
96                                             0.0f, 0.0f, 2.0f, 1.0f);
97
98   /* Render all of the images in the texture using coordinates from a
99      CoglPrimitive */
100   v = verts = g_new (Vert, 4 * TEX_DEPTH);
101   for (i = 0; i < TEX_DEPTH; i++)
102     {
103       float r = (i + 0.5f) / TEX_DEPTH;
104
105       v->x = i * TEX_WIDTH;
106       v->y = TEX_HEIGHT;
107       v->s = 0;
108       v->t = 0;
109       v->r = r;
110       v++;
111
112       v->x = i * TEX_WIDTH;
113       v->y = TEX_HEIGHT * 2;
114       v->s = 0;
115       v->t = 1;
116       v->r = r;
117       v++;
118
119       v->x = i * TEX_WIDTH + TEX_WIDTH;
120       v->y = TEX_HEIGHT * 2;
121       v->s = 1;
122       v->t = 1;
123       v->r = r;
124       v++;
125
126       v->x = i * TEX_WIDTH + TEX_WIDTH;
127       v->y = TEX_HEIGHT;
128       v->s = 1;
129       v->t = 0;
130       v->r = r;
131       v++;
132     }
133
134   attribute_buffer = cogl_attribute_buffer_new (ctx,
135                                                 4 * TEX_DEPTH * sizeof (Vert),
136                                                 verts);
137   attributes[0] = cogl_attribute_new (attribute_buffer,
138                                       "cogl_position_in",
139                                       sizeof (Vert),
140                                       G_STRUCT_OFFSET (Vert, x),
141                                       2, /* n_components */
142                                       COGL_ATTRIBUTE_TYPE_FLOAT);
143   attributes[1] = cogl_attribute_new (attribute_buffer,
144                                       "cogl_tex_coord_in",
145                                       sizeof (Vert),
146                                       G_STRUCT_OFFSET (Vert, s),
147                                       3, /* n_components */
148                                       COGL_ATTRIBUTE_TYPE_FLOAT);
149   primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
150                                                   6 * TEX_DEPTH,
151                                                   attributes,
152                                                   2 /* n_attributes */);
153
154   cogl_primitive_set_indices (primitive,
155                               cogl_get_rectangle_indices (ctx,
156                                                           TEX_DEPTH),
157                               6 * TEX_DEPTH);
158
159   cogl_framebuffer_draw_primitive (fb, pipeline, primitive);
160
161   g_free (verts);
162
163   cogl_object_unref (primitive);
164   cogl_object_unref (attributes[0]);
165   cogl_object_unref (attributes[1]);
166   cogl_object_unref (attribute_buffer);
167   cogl_object_unref (pipeline);
168 }
169
170 static void
171 validate_block (int block_x, int block_y, int z)
172 {
173   int x, y;
174
175   for (y = 0; y < TEX_HEIGHT; y++)
176     for (x = 0; x < TEX_WIDTH; x++)
177       test_utils_check_pixel_rgb (fb,
178                                   block_x * TEX_WIDTH + x,
179                                   block_y * TEX_HEIGHT + y,
180                                   255 - x * 8,
181                                   y * 8,
182                                   255 - z * 8);
183 }
184
185 static void
186 validate_result (void)
187 {
188   int i;
189
190   validate_block (0, 0, 0);
191
192   for (i = 0; i < TEX_DEPTH; i++)
193     validate_block (i, 1, i);
194 }
195
196 static void
197 test_multi_texture (TestState *state)
198 {
199   CoglPipeline *pipeline;
200   CoglTexture3D *tex_3d;
201   CoglTexture2D *tex_2d;
202   guint8 tex_data[4];
203
204   cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
205
206   /* Tests a pipeline that is using multi-texturing to combine a 3D
207      texture with a 2D texture. The texture from another layer is
208      sampled with TEXTURE_? just to pick up a specific bug that was
209      happening with the ARBfp fragend */
210
211   pipeline = cogl_pipeline_new (ctx);
212
213   tex_data[0] = 0xff;
214   tex_data[1] = 0x00;
215   tex_data[2] = 0x00;
216   tex_data[3] = 0xff;
217   tex_2d = cogl_texture_2d_new_from_data (ctx,
218                                           1, 1, /* width/height */
219                                           COGL_PIXEL_FORMAT_RGBA_8888_PRE,
220                                           COGL_PIXEL_FORMAT_RGBA_8888_PRE,
221                                           4, /* rowstride */
222                                           tex_data,
223                                           NULL);
224   cogl_pipeline_set_layer_texture (pipeline, 0, COGL_TEXTURE (tex_2d));
225
226   tex_data[0] = 0x00;
227   tex_data[1] = 0xff;
228   tex_data[2] = 0x00;
229   tex_data[3] = 0xff;
230   tex_3d = cogl_texture_3d_new_from_data (ctx,
231                                           1, 1, 1, /* width/height/depth */
232                                           COGL_PIXEL_FORMAT_RGBA_8888_PRE,
233                                           COGL_PIXEL_FORMAT_RGBA_8888_PRE,
234                                           4, /* rowstride */
235                                           4, /* image_stride */
236                                           tex_data,
237                                           NULL);
238   cogl_pipeline_set_layer_texture (pipeline, 1, COGL_TEXTURE (tex_3d));
239
240   cogl_pipeline_set_layer_combine (pipeline, 0,
241                                    "RGBA = REPLACE(PREVIOUS)",
242                                    NULL);
243   cogl_pipeline_set_layer_combine (pipeline, 1,
244                                    "RGBA = ADD(TEXTURE_0, TEXTURE_1)",
245                                    NULL);
246
247   cogl_framebuffer_draw_rectangle (fb, pipeline, 0, 0, 10, 10);
248
249   test_utils_check_pixel (fb, 5, 5, 0xffff00ff);
250
251   cogl_object_unref (tex_2d);
252   cogl_object_unref (tex_3d);
253   cogl_object_unref (pipeline);
254 }
255
256 void
257 test_texture_3d (void)
258 {
259   /* Check whether GL supports the rectangle extension. If not we'll
260      just assume the test passes */
261   if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
262     {
263       TestState state;
264
265       state.fb_width = cogl_framebuffer_get_width (fb);
266       state.fb_height = cogl_framebuffer_get_height (fb);
267
268       cogl_framebuffer_orthographic (fb,
269                                      0, 0, /* x_1, y_1 */
270                                      state.fb_width, /* x_2 */
271                                      state.fb_height /* y_2 */,
272                                      -1, 100 /* near/far */);
273
274       draw_frame (&state);
275       validate_result ();
276
277       test_multi_texture (&state);
278
279       if (cogl_test_verbose ())
280         g_print ("OK\n");
281     }
282   else if (cogl_test_verbose ())
283     g_print ("Skipping\n");
284 }
285