~darkxst/ubuntu/raring/cogl/lp1163025

« back to all changes in this revision

Viewing changes to cogl/cogl-meta-texture.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-03-13 19:11:11 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120313191111-3hgk529qkh9m6uk2
Tags: 1.9.8-0ubuntu1
* New upstream release (LP: #941617)
* Updated symbols & library name for soname update
* debian/control.in: Bump minimum glib to 2.28
* debian/patches/02_disable_armv5t_specific_optimization.patch: Disabled

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Cogl
 
3
 *
 
4
 * An object oriented GL/GLES Abstraction/Utility Layer
 
5
 *
 
6
 * Copyright (C) 2011 Intel Corporation.
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library. If not, see
 
20
 * <http://www.gnu.org/licenses/>.
 
21
 *
 
22
 *
 
23
 * Authors:
 
24
 *  Robert Bragg   <robert@linux.intel.com>
 
25
 */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#include "config.h"
 
29
#endif
 
30
 
 
31
#include "cogl-texture.h"
 
32
#include "cogl-matrix.h"
 
33
#include "cogl-spans.h"
 
34
#include "cogl-meta-texture.h"
 
35
#include "cogl-texture-rectangle-private.h"
 
36
 
 
37
#include <string.h>
 
38
#include <math.h>
 
39
 
 
40
typedef struct _ForeachData
 
41
{
 
42
  float meta_region_coords[4];
 
43
  CoglPipelineWrapMode wrap_s;
 
44
  CoglPipelineWrapMode wrap_t;
 
45
  CoglMetaTextureCallback callback;
 
46
  void *user_data;
 
47
 
 
48
  int width;
 
49
  int height;
 
50
 
 
51
  CoglTexture *padded_textures[9];
 
52
  const float *grid_slice_texture_coords;
 
53
  float slice_offset_s;
 
54
  float slice_offset_t;
 
55
  float slice_range_s;
 
56
  float slice_range_t;
 
57
} ForeachData;
 
58
 
 
59
static void
 
60
padded_grid_repeat_cb (CoglTexture *slice_texture,
 
61
                       const float *slice_texture_coords,
 
62
                       const float *meta_coords,
 
63
                       void *user_data)
 
64
{
 
65
  ForeachData *data;
 
66
  float mapped_coords[4];
 
67
 
 
68
  /* Ignore padding slices for the current grid */
 
69
  if (!slice_texture)
 
70
    return;
 
71
 
 
72
  data = user_data;
 
73
 
 
74
  /* NB: the slice_texture_coords[] we get here will always be
 
75
   * normalized.
 
76
   *
 
77
   * We now need to map the normalized slice_texture_coords[] we have
 
78
   * here back to the real slice coordinates we saved in the previous
 
79
   * stage...
 
80
   */
 
81
  mapped_coords[0] =
 
82
    slice_texture_coords[0] * data->slice_range_s + data->slice_offset_s;
 
83
  mapped_coords[1] =
 
84
    slice_texture_coords[1] * data->slice_range_t + data->slice_offset_t;
 
85
  mapped_coords[2] =
 
86
    slice_texture_coords[2] * data->slice_range_s + data->slice_offset_s;
 
87
  mapped_coords[3] =
 
88
    slice_texture_coords[3] * data->slice_range_t + data->slice_offset_t;
 
89
 
 
90
  data->callback (slice_texture,
 
91
                  mapped_coords, meta_coords, data->user_data);
 
92
}
 
93
 
 
94
static int
 
95
setup_padded_spans (CoglSpan *spans,
 
96
                    float start,
 
97
                    float end,
 
98
                    float range,
 
99
                    int *real_index)
 
100
{
 
101
  int span_index = 0;
 
102
 
 
103
  if (start > 0)
 
104
    {
 
105
      spans[0].start = 0;
 
106
      spans[0].size = start;
 
107
      spans[0].waste = 0;
 
108
      span_index++;
 
109
      spans[1].start = spans[0].size;
 
110
    }
 
111
  else
 
112
    spans[span_index].start = 0;
 
113
 
 
114
  spans[span_index].size = end - start;
 
115
  spans[span_index].waste = 0;
 
116
  *real_index = span_index;
 
117
  span_index++;
 
118
 
 
119
  if (end < range)
 
120
    {
 
121
      spans[span_index].start =
 
122
        spans[span_index - 1].start + spans[span_index - 1].size;
 
123
      spans[span_index].size = range - end;
 
124
      spans[span_index].waste = 0;
 
125
      span_index++;
 
126
    }
 
127
 
 
128
  return span_index;
 
129
}
 
130
 
 
131
/* This handles each sub-texture within the range [0,1] of our
 
132
 * original meta texture and repeats each one separately across the
 
133
 * users requested virtual texture coordinates.
 
134
 *
 
135
 * A notable advantage of this approach is that we will batch
 
136
 * together callbacks corresponding to the same underlying slice
 
137
 * together.
 
138
 */
 
139
void
 
140
create_grid_and_repeat_cb (CoglTexture *slice_texture,
 
141
                           const float *slice_texture_coords,
 
142
                           const float *meta_coords,
 
143
                           void *user_data)
 
144
{
 
145
  ForeachData *data = user_data;
 
146
  CoglSpan x_spans[3];
 
147
  int n_x_spans;
 
148
  int x_real_index;
 
149
  CoglSpan y_spans[3];
 
150
  int n_y_spans;
 
151
  int y_real_index;
 
152
 
 
153
  /* NB: This callback is called for each slice of the meta-texture
 
154
   * in the range [0,1].
 
155
   *
 
156
   * We define a "padded grid" for each slice of the meta-texture in
 
157
   * the range [0,1]. The x axis and y axis grid lines are defined
 
158
   * using CoglSpans.
 
159
   *
 
160
   * The padded grid maps over the meta-texture coordinates in the
 
161
   * range [0,1] but only contains one valid cell that corresponds to
 
162
   * current slice being iterated and all the surrounding cells just
 
163
   * provide padding.
 
164
   *
 
165
   * Once we've defined our padded grid we then repeat that across
 
166
   * the user's original region, calling their callback whenever
 
167
   * we see our current slice - ignoring padding.
 
168
   *
 
169
   * NB: we can assume meta_coords[] are normalized at this point
 
170
   * since TextureRectangles aren't iterated with this code-path.
 
171
   *
 
172
   * NB: spans are always defined using non-normalized coordinates
 
173
   */
 
174
  n_x_spans = setup_padded_spans (x_spans,
 
175
                                  meta_coords[0] * data->width,
 
176
                                  meta_coords[2] * data->width,
 
177
                                  data->width,
 
178
                                  &x_real_index);
 
179
  n_y_spans = setup_padded_spans (y_spans,
 
180
                                  meta_coords[1] * data->height,
 
181
                                  meta_coords[3] * data->height,
 
182
                                  data->height,
 
183
                                  &y_real_index);
 
184
 
 
185
  data->padded_textures[n_y_spans * y_real_index + x_real_index] =
 
186
    slice_texture;
 
187
 
 
188
  /* Our callback is going to be passed normalized slice texture
 
189
   * coordinates, and we will need to map the range [0,1] to the real
 
190
   * slice_texture_coords we have here... */
 
191
  data->grid_slice_texture_coords = slice_texture_coords;
 
192
  data->slice_range_s = fabs (data->grid_slice_texture_coords[2] -
 
193
                              data->grid_slice_texture_coords[0]);
 
194
  data->slice_range_t = fabs (data->grid_slice_texture_coords[3] -
 
195
                              data->grid_slice_texture_coords[1]);
 
196
  data->slice_offset_s = MIN (data->grid_slice_texture_coords[0],
 
197
                              data->grid_slice_texture_coords[2]);
 
198
  data->slice_offset_t = MIN (data->grid_slice_texture_coords[1],
 
199
                              data->grid_slice_texture_coords[3]);
 
200
 
 
201
  /* Now actually iterate the region the user originally requested
 
202
   * using the current padded grid */
 
203
  _cogl_texture_spans_foreach_in_region (x_spans,
 
204
                                         n_x_spans,
 
205
                                         y_spans,
 
206
                                         n_y_spans,
 
207
                                         data->padded_textures,
 
208
                                         data->meta_region_coords,
 
209
                                         data->width,
 
210
                                         data->height,
 
211
                                         data->wrap_s,
 
212
                                         data->wrap_t,
 
213
                                         padded_grid_repeat_cb,
 
214
                                         data);
 
215
 
 
216
  /* Clear the padded_textures ready for the next iteration */
 
217
  data->padded_textures[n_y_spans * y_real_index + x_real_index] = NULL;
 
218
}
 
219
 
 
220
#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
 
221
 
 
222
typedef struct _ClampData
 
223
{
 
224
  float start;
 
225
  float end;
 
226
  gboolean s_flipped;
 
227
  gboolean t_flipped;
 
228
  CoglMetaTextureCallback callback;
 
229
  void *user_data;
 
230
} ClampData;
 
231
 
 
232
static void
 
233
clamp_s_cb (CoglTexture *sub_texture,
 
234
            const float *sub_texture_coords,
 
235
            const float *meta_coords,
 
236
            void *user_data)
 
237
{
 
238
  ClampData *clamp_data = user_data;
 
239
  float mapped_meta_coords[4] = {
 
240
    clamp_data->start,
 
241
    meta_coords[1],
 
242
    clamp_data->end,
 
243
    meta_coords[3]
 
244
  };
 
245
  if (clamp_data->s_flipped)
 
246
    SWAP (mapped_meta_coords[0], mapped_meta_coords[2]);
 
247
  /* NB: we never need to flip the t coords when dealing with
 
248
   * s-axis clamping so no need to check if ->t_flipped */
 
249
  clamp_data->callback (sub_texture,
 
250
                        sub_texture_coords, mapped_meta_coords,
 
251
                        clamp_data->user_data);
 
252
}
 
253
 
 
254
static void
 
255
clamp_t_cb (CoglTexture *sub_texture,
 
256
            const float *sub_texture_coords,
 
257
            const float *meta_coords,
 
258
            void *user_data)
 
259
{
 
260
  ClampData *clamp_data = user_data;
 
261
  float mapped_meta_coords[4] = {
 
262
    meta_coords[0],
 
263
    clamp_data->start,
 
264
    meta_coords[2],
 
265
    clamp_data->end,
 
266
  };
 
267
  if (clamp_data->s_flipped)
 
268
    SWAP (mapped_meta_coords[0], mapped_meta_coords[2]);
 
269
  if (clamp_data->t_flipped)
 
270
    SWAP (mapped_meta_coords[1], mapped_meta_coords[3]);
 
271
  clamp_data->callback (sub_texture,
 
272
                        sub_texture_coords, mapped_meta_coords,
 
273
                        clamp_data->user_data);
 
274
}
 
275
 
 
276
static gboolean
 
277
foreach_clamped_region (CoglMetaTexture *meta_texture,
 
278
                        float *tx_1,
 
279
                        float *ty_1,
 
280
                        float *tx_2,
 
281
                        float *ty_2,
 
282
                        CoglPipelineWrapMode wrap_s,
 
283
                        CoglPipelineWrapMode wrap_t,
 
284
                        CoglMetaTextureCallback callback,
 
285
                        void *user_data)
 
286
{
 
287
  float width = cogl_texture_get_width (COGL_TEXTURE (meta_texture));
 
288
  ClampData clamp_data;
 
289
 
 
290
  /* Consider that *tx_1 may be > *tx_2 and to simplify things
 
291
   * we just flip them around if that's the case and keep a note
 
292
   * of the fact that they are flipped. */
 
293
  if (*tx_1 > *tx_2)
 
294
    {
 
295
      SWAP (*tx_1, *tx_2);
 
296
      clamp_data.s_flipped = TRUE;
 
297
    }
 
298
  else
 
299
    clamp_data.s_flipped = FALSE;
 
300
 
 
301
  /* The same goes for ty_1 and ty_2... */
 
302
  if (*ty_1 > *ty_2)
 
303
    {
 
304
      SWAP (*ty_1, *ty_2);
 
305
      clamp_data.t_flipped = TRUE;
 
306
    }
 
307
  else
 
308
    clamp_data.t_flipped = FALSE;
 
309
 
 
310
  clamp_data.callback = callback;
 
311
  clamp_data.user_data = user_data;
 
312
 
 
313
  if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
 
314
    {
 
315
      float max_s_coord;
 
316
      float half_texel_width;
 
317
 
 
318
      /* Consider that rectangle textures have non-normalized
 
319
       * coordinates... */
 
320
      if (cogl_is_texture_rectangle (meta_texture))
 
321
        max_s_coord = width;
 
322
      else
 
323
        max_s_coord = 1.0;
 
324
 
 
325
      half_texel_width = max_s_coord / (width * 2);
 
326
 
 
327
      /* Handle any left clamped region */
 
328
      if (*tx_1 < 0)
 
329
        {
 
330
          clamp_data.start = *tx_1;
 
331
          clamp_data.end = MIN (0, *tx_2);;
 
332
          cogl_meta_texture_foreach_in_region (meta_texture,
 
333
                                               half_texel_width, *ty_1,
 
334
                                               half_texel_width, *ty_2,
 
335
                                               COGL_PIPELINE_WRAP_MODE_REPEAT,
 
336
                                               wrap_t,
 
337
                                               clamp_s_cb,
 
338
                                               &clamp_data);
 
339
          /* Have we handled everything? */
 
340
          if (tx_2 <= 0)
 
341
            return TRUE;
 
342
 
 
343
          /* clamp tx_1 since we've handled everything with x < 0 */
 
344
          *tx_1 = 0;
 
345
        }
 
346
 
 
347
      /* Handle any right clamped region - including the corners */
 
348
      if (*tx_2 > max_s_coord)
 
349
        {
 
350
          clamp_data.start = MAX (max_s_coord, *tx_1);
 
351
          clamp_data.end = *tx_2;
 
352
          cogl_meta_texture_foreach_in_region (meta_texture,
 
353
                                               max_s_coord - half_texel_width,
 
354
                                               *ty_1,
 
355
                                               max_s_coord - half_texel_width,
 
356
                                               *ty_2,
 
357
                                               COGL_PIPELINE_WRAP_MODE_REPEAT,
 
358
                                               wrap_t,
 
359
                                               clamp_s_cb,
 
360
                                               &clamp_data);
 
361
          /* Have we handled everything? */
 
362
          if (*tx_1 >= max_s_coord)
 
363
            return TRUE;
 
364
 
 
365
          /* clamp tx_2 since we've handled everything with x >
 
366
           * max_s_coord */
 
367
          *tx_2 = max_s_coord;
 
368
        }
 
369
    }
 
370
 
 
371
  if (wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
 
372
    {
 
373
      float height = cogl_texture_get_height (COGL_TEXTURE (meta_texture));
 
374
      float max_t_coord;
 
375
      float half_texel_height;
 
376
 
 
377
      /* Consider that rectangle textures have non-normalized
 
378
       * coordinates... */
 
379
      if (cogl_is_texture_rectangle (meta_texture))
 
380
        max_t_coord = height;
 
381
      else
 
382
        max_t_coord = 1.0;
 
383
 
 
384
      half_texel_height = max_t_coord / (height * 2);
 
385
 
 
386
      /* Handle any top clamped region */
 
387
      if (*ty_1 < 0)
 
388
        {
 
389
          clamp_data.start = *ty_1;
 
390
          clamp_data.end = MIN (0, *ty_2);;
 
391
          cogl_meta_texture_foreach_in_region (meta_texture,
 
392
                                               *tx_1, half_texel_height,
 
393
                                               *tx_2, half_texel_height,
 
394
                                               wrap_s,
 
395
                                               COGL_PIPELINE_WRAP_MODE_REPEAT,
 
396
                                               clamp_t_cb,
 
397
                                               &clamp_data);
 
398
          /* Have we handled everything? */
 
399
          if (tx_2 <= 0)
 
400
            return TRUE;
 
401
 
 
402
          /* clamp ty_1 since we've handled everything with y < 0 */
 
403
          *ty_1 = 0;
 
404
        }
 
405
 
 
406
      /* Handle any bottom clamped region */
 
407
      if (*ty_2 > max_t_coord)
 
408
        {
 
409
          clamp_data.start = MAX (max_t_coord, *ty_1);;
 
410
          clamp_data.end = *ty_2;
 
411
          cogl_meta_texture_foreach_in_region (meta_texture,
 
412
                                               *tx_1,
 
413
                                               max_t_coord - half_texel_height,
 
414
                                               *tx_2,
 
415
                                               max_t_coord - half_texel_height,
 
416
                                               wrap_s,
 
417
                                               COGL_PIPELINE_WRAP_MODE_REPEAT,
 
418
                                               clamp_t_cb,
 
419
                                               &clamp_data);
 
420
          /* Have we handled everything? */
 
421
          if (*ty_1 >= max_t_coord)
 
422
            return TRUE;
 
423
 
 
424
          /* clamp ty_2 since we've handled everything with y >
 
425
           * max_t_coord */
 
426
          *ty_2 = max_t_coord;
 
427
        }
 
428
    }
 
429
 
 
430
  if (clamp_data.s_flipped)
 
431
    SWAP (*tx_1, *tx_2);
 
432
  if (clamp_data.t_flipped)
 
433
    SWAP (*ty_1, *ty_2);
 
434
 
 
435
  return FALSE;
 
436
}
 
437
 
 
438
typedef struct _NormalizeData
 
439
{
 
440
  CoglMetaTextureCallback callback;
 
441
  void *user_data;
 
442
  float s_normalize_factor;
 
443
  float t_normalize_factor;
 
444
} NormalizeData;
 
445
 
 
446
static void
 
447
normalize_meta_coords_cb (CoglTexture *slice_texture,
 
448
                          const float *slice_coords,
 
449
                          const float *meta_coords,
 
450
                          void *user_data)
 
451
{
 
452
  NormalizeData *data = user_data;
 
453
  float normalized_meta_coords[4] = {
 
454
      meta_coords[0] * data->s_normalize_factor,
 
455
      meta_coords[1] * data->t_normalize_factor,
 
456
      meta_coords[2] * data->s_normalize_factor,
 
457
      meta_coords[3] * data->t_normalize_factor
 
458
  };
 
459
 
 
460
  data->callback (slice_texture,
 
461
                  slice_coords, normalized_meta_coords,
 
462
                  data->user_data);
 
463
}
 
464
 
 
465
typedef struct _UnNormalizeData
 
466
{
 
467
  CoglMetaTextureCallback callback;
 
468
  void *user_data;
 
469
  float width;
 
470
  float height;
 
471
} UnNormalizeData;
 
472
 
 
473
static void
 
474
un_normalize_slice_coords_cb (CoglTexture *slice_texture,
 
475
                              const float *slice_coords,
 
476
                              const float *meta_coords,
 
477
                              void *user_data)
 
478
{
 
479
  UnNormalizeData *data = user_data;
 
480
  float un_normalized_slice_coords[4] = {
 
481
    slice_coords[0] * data->width,
 
482
    slice_coords[1] * data->height,
 
483
    slice_coords[2] * data->width,
 
484
    slice_coords[3] * data->height
 
485
  };
 
486
 
 
487
  data->callback (slice_texture,
 
488
                  un_normalized_slice_coords, meta_coords,
 
489
                  data->user_data);
 
490
}
 
491
 
 
492
void
 
493
cogl_meta_texture_foreach_in_region (CoglMetaTexture *meta_texture,
 
494
                                     float tx_1,
 
495
                                     float ty_1,
 
496
                                     float tx_2,
 
497
                                     float ty_2,
 
498
                                     CoglPipelineWrapMode wrap_s,
 
499
                                     CoglPipelineWrapMode wrap_t,
 
500
                                     CoglMetaTextureCallback callback,
 
501
                                     void *user_data)
 
502
{
 
503
  CoglTexture *texture = COGL_TEXTURE (meta_texture);
 
504
  float width = cogl_texture_get_width (texture);
 
505
  float height = cogl_texture_get_height (texture);
 
506
  NormalizeData normalize_data;
 
507
 
 
508
  if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
 
509
    wrap_s = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
 
510
  if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
 
511
    wrap_t = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
 
512
 
 
513
  if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE ||
 
514
      wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
 
515
    {
 
516
      gboolean finished = foreach_clamped_region (meta_texture,
 
517
                                                  &tx_1, &ty_1, &tx_2, &ty_2,
 
518
                                                  wrap_s, wrap_t,
 
519
                                                  callback,
 
520
                                                  user_data);
 
521
      if (finished)
 
522
        return;
 
523
 
 
524
      /* Since clamping has been handled we now want to normalize our
 
525
       * wrap modes we se can assume from this point on we don't
 
526
       * need to consider CLAMP_TO_EDGE. (NB: The spans code will
 
527
       * assert that CLAMP_TO_EDGE isn't requested) */
 
528
      if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
 
529
        wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT;
 
530
      if (wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE)
 
531
        wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT;
 
532
    }
 
533
 
 
534
  /* It makes things simpler to deal with non-normalized region
 
535
   * coordinates beyond this point and only re-normalize just before
 
536
   * calling the user's callback... */
 
537
 
 
538
  if (!cogl_is_texture_rectangle (COGL_TEXTURE (meta_texture)))
 
539
    {
 
540
      normalize_data.callback = callback;
 
541
      normalize_data.user_data = user_data;
 
542
      normalize_data.s_normalize_factor = 1.0f / width;
 
543
      normalize_data.t_normalize_factor = 1.0f / height;
 
544
      callback = normalize_meta_coords_cb;
 
545
      user_data = &normalize_data;
 
546
      tx_1 *= width;
 
547
      ty_1 *= height;
 
548
      tx_2 *= width;
 
549
      ty_2 *= height;
 
550
    }
 
551
 
 
552
  /* XXX: at some point this wont be routed through the CoglTexture
 
553
   * vtable, instead there will be a separate CoglMetaTexture
 
554
   * interface vtable. */
 
555
 
 
556
  if (texture->vtable->foreach_sub_texture_in_region)
 
557
    {
 
558
      ForeachData data;
 
559
 
 
560
      data.meta_region_coords[0] = tx_1;
 
561
      data.meta_region_coords[1] = ty_1;
 
562
      data.meta_region_coords[2] = tx_2;
 
563
      data.meta_region_coords[3] = ty_2;
 
564
      data.wrap_s = wrap_s;
 
565
      data.wrap_t = wrap_t;
 
566
      data.callback = callback;
 
567
      data.user_data = user_data;
 
568
 
 
569
      data.width = width;
 
570
      data.height = height;
 
571
 
 
572
      memset (data.padded_textures, 0, sizeof (data.padded_textures));
 
573
 
 
574
      /*
 
575
       * 1) We iterate all the slices of the meta-texture only within
 
576
       *    the range [0,1].
 
577
       *
 
578
       * 2) We define a "padded grid" for each slice of the
 
579
       *    meta-texture in the range [0,1].
 
580
       *
 
581
       *    The padded grid maps over the meta-texture coordinates in
 
582
       *    the range [0,1] but only contains one valid cell that
 
583
       *    corresponds to current slice being iterated and all the
 
584
       *    surrounding cells just provide padding.
 
585
       *
 
586
       * 3) Once we've defined our padded grid we then repeat that
 
587
       *    across the user's original region, calling their callback
 
588
       *    whenever we see our current slice - ignoring padding.
 
589
       *
 
590
       * A notable benefit of this design is that repeating a texture
 
591
       * made of multiple slices will result in us repeating each
 
592
       * slice in-turn so the user gets repeat callbacks for the same
 
593
       * texture batched together. For manual emulation of texture
 
594
       * repeats done by drawing geometry this makes it more likely
 
595
       * that we can batch geometry.
 
596
       */
 
597
 
 
598
      texture->vtable->foreach_sub_texture_in_region (texture,
 
599
                                                      0, 0, 1, 1,
 
600
                                                      create_grid_and_repeat_cb,
 
601
                                                      &data);
 
602
    }
 
603
  else
 
604
    {
 
605
      CoglSpan x_span = { 0, width, 0 };
 
606
      CoglSpan y_span = { 0, height, 0 };
 
607
      float meta_region_coords[4] = { tx_1, ty_1, tx_2, ty_2 };
 
608
      UnNormalizeData un_normalize_data;
 
609
 
 
610
      /* If we are dealing with a CoglTextureRectangle then we need a shim
 
611
       * callback that un_normalizes the slice coordinates we get from
 
612
       * _cogl_texture_spans_foreach_in_region before passing them to
 
613
       * the user's callback. */
 
614
      if (cogl_is_texture_rectangle (meta_texture))
 
615
        {
 
616
          un_normalize_data.callback = callback;
 
617
          un_normalize_data.user_data = user_data;
 
618
          un_normalize_data.width = width;
 
619
          un_normalize_data.height = height;
 
620
          callback = un_normalize_slice_coords_cb;
 
621
          user_data = &un_normalize_data;
 
622
        }
 
623
 
 
624
      _cogl_texture_spans_foreach_in_region (&x_span, 1,
 
625
                                             &y_span, 1,
 
626
                                             &texture,
 
627
                                             meta_region_coords,
 
628
                                             width,
 
629
                                             height,
 
630
                                             wrap_s,
 
631
                                             wrap_t,
 
632
                                             callback,
 
633
                                             user_data);
 
634
    }
 
635
}
 
636
#undef SWAP