~oem-solutions-group/unity-2d/clutter-1.0

« back to all changes in this revision

Viewing changes to clutter/cogl/cogl/cogl-texture-2d-sliced.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

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) 2007,2008,2009 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 <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 *
 
22
 *
 
23
 * Authors:
 
24
 *  Matthew Allum  <mallum@openedhand.com>
 
25
 *  Neil Roberts   <neil@linux.intel.com>
 
26
 *  Robert Bragg   <robert@linux.intel.com>
 
27
 */
 
28
 
 
29
#ifdef HAVE_CONFIG_H
 
30
#include "config.h"
 
31
#endif
 
32
 
 
33
#include "cogl.h"
 
34
#include "cogl-internal.h"
 
35
#include "cogl-util.h"
 
36
#include "cogl-bitmap.h"
 
37
#include "cogl-bitmap-private.h"
 
38
#include "cogl-texture-private.h"
 
39
#include "cogl-texture-2d-sliced-private.h"
 
40
#include "cogl-texture-driver.h"
 
41
#include "cogl-context.h"
 
42
#include "cogl-handle.h"
 
43
#include "cogl-spans.h"
 
44
#include "cogl-journal-private.h"
 
45
 
 
46
#include <string.h>
 
47
#include <stdlib.h>
 
48
#include <math.h>
 
49
 
 
50
static void _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds);
 
51
 
 
52
COGL_HANDLE_DEFINE (Texture2DSliced, texture_2d_sliced);
 
53
 
 
54
static const CoglTextureVtable cogl_texture_2d_sliced_vtable;
 
55
 
 
56
/* To differentiate between texture coordinates of a specific, real, slice
 
57
 * texture and the texture coordinates of the composite, sliced texture, the
 
58
 * coordinates of the sliced texture are called "virtual" coordinates and the
 
59
 * coordinates of slices are called "slice" coordinates. */
 
60
/* This function lets you iterate all the slices that lie within the given
 
61
 * virtual coordinates of the parent sliced texture. */
 
62
/* Note: no guarantee is given about the order in which the slices will be
 
63
 * visited */
 
64
static void
 
65
_cogl_texture_2d_sliced_foreach_sub_texture_in_region (
 
66
                                       CoglTexture *tex,
 
67
                                       float virtual_tx_1,
 
68
                                       float virtual_ty_1,
 
69
                                       float virtual_tx_2,
 
70
                                       float virtual_ty_2,
 
71
                                       CoglTextureSliceCallback callback,
 
72
                                       void *user_data)
 
73
{
 
74
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
75
  float width = tex_2ds->width;
 
76
  float height = tex_2ds->height;
 
77
  CoglSpanIter iter_x;
 
78
  CoglSpanIter iter_y;
 
79
 
 
80
  /* Slice spans are stored in denormalized coordinates, and this is what
 
81
   * the _cogl_span_iter_* funcs expect to be given, so we scale the given
 
82
   * virtual coordinates by the texture size to denormalize.
 
83
   */
 
84
  /* XXX: I wonder if it's worth changing how we store spans so we can avoid
 
85
   * the need to denormalize here */
 
86
  virtual_tx_1 *= width;
 
87
  virtual_ty_1 *= height;
 
88
  virtual_tx_2 *= width;
 
89
  virtual_ty_2 *= height;
 
90
 
 
91
  /* Iterate the y axis of the virtual rectangle */
 
92
  for (_cogl_span_iter_begin (&iter_y,
 
93
                              tex_2ds->slice_y_spans,
 
94
                              height,
 
95
                              virtual_ty_1,
 
96
                              virtual_ty_2);
 
97
       !_cogl_span_iter_end (&iter_y);
 
98
       _cogl_span_iter_next (&iter_y))
 
99
    {
 
100
      float y_intersect_start = iter_y.intersect_start;
 
101
      float y_intersect_end = iter_y.intersect_end;
 
102
      float slice_ty1;
 
103
      float slice_ty2;
 
104
 
 
105
      /* Discard slices out of rectangle early */
 
106
      if (!iter_y.intersects)
 
107
        continue;
 
108
 
 
109
      if (iter_y.flipped)
 
110
        {
 
111
          y_intersect_start = iter_y.intersect_end;
 
112
          y_intersect_end = iter_y.intersect_start;
 
113
        }
 
114
 
 
115
      /* Localize slice texture coordinates */
 
116
      slice_ty1 = y_intersect_start - iter_y.pos;
 
117
      slice_ty2 = y_intersect_end - iter_y.pos;
 
118
 
 
119
      if (tex_2ds->gl_target == GL_TEXTURE_2D)
 
120
        {
 
121
          /* Normalize slice texture coordinates */
 
122
          slice_ty1 /= iter_y.span->size;
 
123
          slice_ty2 /= iter_y.span->size;
 
124
        }
 
125
 
 
126
      /* Iterate the x axis of the virtual rectangle */
 
127
      for (_cogl_span_iter_begin (&iter_x,
 
128
                                  tex_2ds->slice_x_spans,
 
129
                                  width,
 
130
                                  virtual_tx_1,
 
131
                                  virtual_tx_2);
 
132
           !_cogl_span_iter_end (&iter_x);
 
133
           _cogl_span_iter_next (&iter_x))
 
134
        {
 
135
          float slice_coords[4];
 
136
          float virtual_coords[4];
 
137
          float x_intersect_start = iter_x.intersect_start;
 
138
          float x_intersect_end = iter_x.intersect_end;
 
139
          float slice_tx1;
 
140
          float slice_tx2;
 
141
          GLuint gl_handle;
 
142
 
 
143
          /* Discard slices out of rectangle early */
 
144
          if (!iter_x.intersects)
 
145
            continue;
 
146
 
 
147
          if (iter_x.flipped)
 
148
            {
 
149
              x_intersect_start = iter_x.intersect_end;
 
150
              x_intersect_end = iter_x.intersect_start;
 
151
            }
 
152
 
 
153
          /* Localize slice texture coordinates */
 
154
          slice_tx1 = x_intersect_start - iter_x.pos;
 
155
          slice_tx2 = x_intersect_end - iter_x.pos;
 
156
 
 
157
          /* Pluck out opengl texture object for this slice */
 
158
          gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint,
 
159
                                     iter_y.index * iter_x.array->len +
 
160
                                     iter_x.index);
 
161
 
 
162
          if (tex_2ds->gl_target == GL_TEXTURE_2D)
 
163
            {
 
164
              /* Normalize slice texture coordinates */
 
165
              slice_tx1 /= iter_x.span->size;
 
166
              slice_tx2 /= iter_x.span->size;
 
167
            }
 
168
 
 
169
          slice_coords[0] = slice_tx1;
 
170
          slice_coords[1] = slice_ty1;
 
171
          slice_coords[2] = slice_tx2;
 
172
          slice_coords[3] = slice_ty2;
 
173
 
 
174
          virtual_coords[0] = x_intersect_start / width;
 
175
          virtual_coords[1] = y_intersect_start / height;
 
176
          virtual_coords[2] = x_intersect_end / width;
 
177
          virtual_coords[3] = y_intersect_end / height;
 
178
 
 
179
          callback (tex,
 
180
                    gl_handle,
 
181
                    tex_2ds->gl_target,
 
182
                    slice_coords,
 
183
                    virtual_coords,
 
184
                    user_data);
 
185
        }
 
186
    }
 
187
}
 
188
 
 
189
static guint8 *
 
190
_cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds,
 
191
                                               CoglPixelFormat format)
 
192
{
 
193
  CoglSpan *last_x_span;
 
194
  CoglSpan *last_y_span;
 
195
  guint8   *waste_buf = NULL;
 
196
 
 
197
  /* If the texture has any waste then allocate a buffer big enough to
 
198
     fill the gaps */
 
199
  last_x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan,
 
200
                                tex_2ds->slice_x_spans->len - 1);
 
201
  last_y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan,
 
202
                                tex_2ds->slice_y_spans->len - 1);
 
203
  if (last_x_span->waste > 0 || last_y_span->waste > 0)
 
204
    {
 
205
      int bpp = _cogl_get_format_bpp (format);
 
206
      CoglSpan  *first_x_span
 
207
        = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0);
 
208
      CoglSpan  *first_y_span
 
209
        = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, 0);
 
210
      unsigned int right_size = first_y_span->size * last_x_span->waste;
 
211
      unsigned int bottom_size = first_x_span->size * last_y_span->waste;
 
212
 
 
213
      waste_buf = g_malloc (MAX (right_size, bottom_size) * bpp);
 
214
    }
 
215
 
 
216
  return waste_buf;
 
217
}
 
218
 
 
219
static gboolean
 
220
_cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
 
221
                                      CoglBitmap          *bmp,
 
222
                                      GLenum               gl_intformat,
 
223
                                      GLenum               gl_format,
 
224
                                      GLenum               gl_type)
 
225
{
 
226
  CoglSpan  *x_span;
 
227
  CoglSpan  *y_span;
 
228
  GLuint     gl_handle;
 
229
  int        bpp;
 
230
  int        x, y;
 
231
  guint8    *waste_buf;
 
232
 
 
233
  bpp = _cogl_get_format_bpp (bmp->format);
 
234
 
 
235
  waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds,
 
236
                                                             bmp->format);
 
237
 
 
238
  /* Iterate vertical slices */
 
239
  for (y = 0; y < tex_2ds->slice_y_spans->len; ++y)
 
240
    {
 
241
      y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y);
 
242
 
 
243
      /* Iterate horizontal slices */
 
244
      for (x = 0; x < tex_2ds->slice_x_spans->len; ++x)
 
245
        {
 
246
          int slice_num = y * tex_2ds->slice_x_spans->len + x;
 
247
 
 
248
          x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x);
 
249
 
 
250
          /* Pick the gl texture object handle */
 
251
          gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, slice_num);
 
252
 
 
253
          _cogl_texture_driver_upload_subregion_to_gl (
 
254
                                     tex_2ds->gl_target,
 
255
                                     gl_handle,
 
256
                                     x_span->start, /* src x */
 
257
                                     y_span->start, /* src y */
 
258
                                     0, /* dst x */
 
259
                                     0, /* dst y */
 
260
                                     x_span->size - x_span->waste, /* width */
 
261
                                     y_span->size - y_span->waste, /* height */
 
262
                                     bmp,
 
263
                                     gl_format,
 
264
                                     gl_type);
 
265
 
 
266
          /* Keep a copy of the first pixel if needed */
 
267
          if (tex_2ds->first_pixels)
 
268
            {
 
269
              memcpy (tex_2ds->first_pixels[slice_num].data,
 
270
                      bmp->data + x_span->start * bpp
 
271
                      + y_span->start * bmp->rowstride,
 
272
                      bpp);
 
273
              tex_2ds->first_pixels[slice_num].gl_format = gl_format;
 
274
              tex_2ds->first_pixels[slice_num].gl_type = gl_type;
 
275
            }
 
276
 
 
277
          /* Fill the waste with a copies of the rightmost pixels */
 
278
          if (x_span->waste > 0)
 
279
            {
 
280
              const guint8 *src = bmp->data
 
281
                + y_span->start * bmp->rowstride
 
282
                + (x_span->start + x_span->size - x_span->waste - 1) * bpp;
 
283
              guint8 *dst = waste_buf;
 
284
              unsigned int wx, wy;
 
285
 
 
286
              for (wy = 0; wy < y_span->size - y_span->waste; wy++)
 
287
                {
 
288
                  for (wx = 0; wx < x_span->waste; wx++)
 
289
                    {
 
290
                      memcpy (dst, src, bpp);
 
291
                      dst += bpp;
 
292
                    }
 
293
                  src += bmp->rowstride;
 
294
                }
 
295
 
 
296
              _cogl_texture_driver_prep_gl_for_pixels_upload (
 
297
                                                        x_span->waste * bpp,
 
298
                                                        bpp);
 
299
 
 
300
              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
 
301
                                   x_span->size - x_span->waste,
 
302
                                   0,
 
303
                                   x_span->waste,
 
304
                                   y_span->size - y_span->waste,
 
305
                                   gl_format, gl_type,
 
306
                                   waste_buf) );
 
307
            }
 
308
 
 
309
          if (y_span->waste > 0)
 
310
            {
 
311
              const guint8 *src = bmp->data
 
312
                + ((y_span->start + y_span->size - y_span->waste - 1)
 
313
                   * bmp->rowstride)
 
314
                + x_span->start * bpp;
 
315
              guint8 *dst = waste_buf;
 
316
              unsigned int wy, wx;
 
317
 
 
318
              for (wy = 0; wy < y_span->waste; wy++)
 
319
                {
 
320
                  memcpy (dst, src, (x_span->size - x_span->waste) * bpp);
 
321
                  dst += (x_span->size - x_span->waste) * bpp;
 
322
 
 
323
                  for (wx = 0; wx < x_span->waste; wx++)
 
324
                    {
 
325
                      memcpy (dst, dst - bpp, bpp);
 
326
                      dst += bpp;
 
327
                    }
 
328
                }
 
329
 
 
330
              _cogl_texture_driver_prep_gl_for_pixels_upload (
 
331
                                                        x_span->size * bpp,
 
332
                                                        bpp);
 
333
 
 
334
              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
 
335
                                   0,
 
336
                                   y_span->size - y_span->waste,
 
337
                                   x_span->size,
 
338
                                   y_span->waste,
 
339
                                   gl_format, gl_type,
 
340
                                   waste_buf) );
 
341
            }
 
342
        }
 
343
    }
 
344
 
 
345
  if (waste_buf)
 
346
    g_free (waste_buf);
 
347
 
 
348
  tex_2ds->mipmaps_dirty = TRUE;
 
349
 
 
350
  return TRUE;
 
351
}
 
352
 
 
353
static gboolean
 
354
_cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
 
355
                                                int          src_x,
 
356
                                                int          src_y,
 
357
                                                int          dst_x,
 
358
                                                int          dst_y,
 
359
                                                int          width,
 
360
                                                int          height,
 
361
                                                CoglBitmap  *source_bmp,
 
362
                                                GLuint       source_gl_format,
 
363
                                                GLuint       source_gl_type)
 
364
{
 
365
  CoglSpan *x_span;
 
366
  CoglSpan *y_span;
 
367
  int               bpp;
 
368
  CoglSpanIter      x_iter;
 
369
  CoglSpanIter      y_iter;
 
370
  GLuint            gl_handle;
 
371
  int               source_x = 0, source_y = 0;
 
372
  int               inter_w = 0, inter_h = 0;
 
373
  int               local_x = 0, local_y = 0;
 
374
  guint8           *waste_buf;
 
375
 
 
376
  bpp = _cogl_get_format_bpp (source_bmp->format);
 
377
 
 
378
  waste_buf =
 
379
    _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds, source_bmp->format);
 
380
 
 
381
  /* Iterate vertical spans */
 
382
  for (source_y = src_y,
 
383
       _cogl_span_iter_begin (&y_iter,
 
384
                              tex_2ds->slice_y_spans,
 
385
                              tex_2ds->height,
 
386
                              dst_y,
 
387
                              dst_y + height);
 
388
 
 
389
       !_cogl_span_iter_end (&y_iter);
 
390
 
 
391
       _cogl_span_iter_next (&y_iter),
 
392
       source_y += inter_h )
 
393
    {
 
394
      /* Discard slices out of the subregion early */
 
395
      if (!y_iter.intersects)
 
396
        {
 
397
          inter_h = 0;
 
398
          continue;
 
399
        }
 
400
 
 
401
      y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan,
 
402
                               y_iter.index);
 
403
 
 
404
      /* Iterate horizontal spans */
 
405
      for (source_x = src_x,
 
406
           _cogl_span_iter_begin (&x_iter,
 
407
                                  tex_2ds->slice_x_spans,
 
408
                                  tex_2ds->width,
 
409
                                  dst_x,
 
410
                                  dst_x + width);
 
411
 
 
412
           !_cogl_span_iter_end (&x_iter);
 
413
 
 
414
           _cogl_span_iter_next (&x_iter),
 
415
           source_x += inter_w )
 
416
        {
 
417
          int slice_num;
 
418
 
 
419
          /* Discard slices out of the subregion early */
 
420
          if (!x_iter.intersects)
 
421
            {
 
422
              inter_w = 0;
 
423
              continue;
 
424
            }
 
425
 
 
426
          x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan,
 
427
                                   x_iter.index);
 
428
 
 
429
          /* Pick intersection width and height */
 
430
          inter_w =  (x_iter.intersect_end - x_iter.intersect_start);
 
431
          inter_h =  (y_iter.intersect_end - y_iter.intersect_start);
 
432
 
 
433
          /* Localize intersection top-left corner to slice*/
 
434
          local_x =  (x_iter.intersect_start - x_iter.pos);
 
435
          local_y =  (y_iter.intersect_start - y_iter.pos);
 
436
 
 
437
          slice_num = y_iter.index * tex_2ds->slice_x_spans->len + x_iter.index;
 
438
 
 
439
          /* Pick slice GL handle */
 
440
          gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, slice_num);
 
441
 
 
442
          _cogl_texture_driver_upload_subregion_to_gl (tex_2ds->gl_target,
 
443
                                                       gl_handle,
 
444
                                                       source_x,
 
445
                                                       source_y,
 
446
                                                       local_x, /* dst x */
 
447
                                                       local_y, /* dst x */
 
448
                                                       inter_w, /* width */
 
449
                                                       inter_h, /* height */
 
450
                                                       source_bmp,
 
451
                                                       source_gl_format,
 
452
                                                       source_gl_type);
 
453
 
 
454
          /* Keep a copy of the first pixel if needed */
 
455
          if (tex_2ds->first_pixels && local_x == 0 && local_y == 0)
 
456
            {
 
457
              memcpy (tex_2ds->first_pixels[slice_num].data,
 
458
                      source_bmp->data + source_x * bpp
 
459
                      + source_y * source_bmp->rowstride,
 
460
                      bpp);
 
461
              tex_2ds->first_pixels[slice_num].gl_format = source_gl_format;
 
462
              tex_2ds->first_pixels[slice_num].gl_type = source_gl_type;
 
463
            }
 
464
 
 
465
          /* If the x_span is sliced and the upload touches the
 
466
             rightmost pixels then fill the waste with copies of the
 
467
             pixels */
 
468
          if (x_span->waste > 0
 
469
              && local_x < x_span->size - x_span->waste
 
470
              && local_x + inter_w >= x_span->size - x_span->waste)
 
471
            {
 
472
              const guint8 *src;
 
473
              guint8 *dst;
 
474
              unsigned int wx, wy;
 
475
 
 
476
              src = source_bmp->data
 
477
                + (src_y +  ((int)y_iter.intersect_start)
 
478
                   - dst_y)
 
479
                * source_bmp->rowstride
 
480
                + (src_x + x_span->start + x_span->size - x_span->waste
 
481
                   - dst_x - 1)
 
482
                * bpp;
 
483
 
 
484
              dst = waste_buf;
 
485
 
 
486
              for (wy = 0; wy < inter_h; wy++)
 
487
                {
 
488
                  for (wx = 0; wx < x_span->waste; wx++)
 
489
                    {
 
490
                      memcpy (dst, src, bpp);
 
491
                      dst += bpp;
 
492
                    }
 
493
                  src += source_bmp->rowstride;
 
494
                }
 
495
 
 
496
              _cogl_texture_driver_prep_gl_for_pixels_upload (
 
497
                                                        x_span->waste * bpp,
 
498
                                                        bpp);
 
499
 
 
500
              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
 
501
                                   x_span->size - x_span->waste,
 
502
                                   local_y,
 
503
                                   x_span->waste,
 
504
                                   inter_h,
 
505
                                   source_gl_format,
 
506
                                   source_gl_type,
 
507
                                   waste_buf) );
 
508
            }
 
509
 
 
510
          /* same for the bottom-most pixels */
 
511
          if (y_span->waste > 0
 
512
              && local_y < y_span->size - y_span->waste
 
513
              && local_y + inter_h >= y_span->size - y_span->waste)
 
514
            {
 
515
              const guint8 *src;
 
516
              guint8 *dst;
 
517
              unsigned int wy, wx;
 
518
              unsigned int copy_width;
 
519
 
 
520
              src = source_bmp->data
 
521
                + (src_x +  ((int)x_iter.intersect_start)
 
522
                   - dst_x)
 
523
                * bpp
 
524
                + (src_y + y_span->start + y_span->size - y_span->waste
 
525
                   - dst_y - 1)
 
526
                * source_bmp->rowstride;
 
527
 
 
528
              dst = waste_buf;
 
529
 
 
530
              if (local_x + inter_w >= x_span->size - x_span->waste)
 
531
                copy_width = x_span->size - local_x;
 
532
              else
 
533
                copy_width = inter_w;
 
534
 
 
535
              for (wy = 0; wy < y_span->waste; wy++)
 
536
                {
 
537
                  memcpy (dst, src, inter_w * bpp);
 
538
                  dst += inter_w * bpp;
 
539
 
 
540
                  for (wx = inter_w; wx < copy_width; wx++)
 
541
                    {
 
542
                      memcpy (dst, dst - bpp, bpp);
 
543
                      dst += bpp;
 
544
                    }
 
545
                }
 
546
 
 
547
              _cogl_texture_driver_prep_gl_for_pixels_upload (
 
548
                                                          copy_width * bpp,
 
549
                                                          bpp);
 
550
 
 
551
              GE( glTexSubImage2D (tex_2ds->gl_target, 0,
 
552
                                   local_x,
 
553
                                   y_span->size - y_span->waste,
 
554
                                   copy_width,
 
555
                                   y_span->waste,
 
556
                                   source_gl_format,
 
557
                                   source_gl_type,
 
558
                                   waste_buf) );
 
559
            }
 
560
        }
 
561
    }
 
562
 
 
563
  if (waste_buf)
 
564
    g_free (waste_buf);
 
565
 
 
566
  tex_2ds->mipmaps_dirty = TRUE;
 
567
 
 
568
  return TRUE;
 
569
}
 
570
 
 
571
static int
 
572
_cogl_rect_slices_for_size (int     size_to_fill,
 
573
                            int     max_span_size,
 
574
                            int     max_waste,
 
575
                            GArray *out_spans)
 
576
{
 
577
  int       n_spans = 0;
 
578
  CoglSpan  span;
 
579
 
 
580
  /* Init first slice span */
 
581
  span.start = 0;
 
582
  span.size = max_span_size;
 
583
  span.waste = 0;
 
584
 
 
585
  /* Repeat until whole area covered */
 
586
  while (size_to_fill >= span.size)
 
587
    {
 
588
      /* Add another slice span of same size */
 
589
      if (out_spans)
 
590
        g_array_append_val (out_spans, span);
 
591
      span.start   += span.size;
 
592
      size_to_fill -= span.size;
 
593
      n_spans++;
 
594
    }
 
595
 
 
596
  /* Add one last smaller slice span */
 
597
  if (size_to_fill > 0)
 
598
    {
 
599
      span.size = size_to_fill;
 
600
      if (out_spans)
 
601
        g_array_append_val (out_spans, span);
 
602
      n_spans++;
 
603
    }
 
604
 
 
605
  return n_spans;
 
606
}
 
607
 
 
608
static int
 
609
_cogl_pot_slices_for_size (int    size_to_fill,
 
610
                           int    max_span_size,
 
611
                           int    max_waste,
 
612
                           GArray *out_spans)
 
613
{
 
614
  int      n_spans = 0;
 
615
  CoglSpan span;
 
616
 
 
617
  /* Init first slice span */
 
618
  span.start = 0;
 
619
  span.size = max_span_size;
 
620
  span.waste = 0;
 
621
 
 
622
  /* Fix invalid max_waste */
 
623
  if (max_waste < 0)
 
624
    max_waste = 0;
 
625
 
 
626
  while (TRUE)
 
627
    {
 
628
      /* Is the whole area covered? */
 
629
      if (size_to_fill > span.size)
 
630
        {
 
631
          /* Not yet - add a span of this size */
 
632
          if (out_spans)
 
633
            g_array_append_val (out_spans, span);
 
634
 
 
635
          span.start   += span.size;
 
636
          size_to_fill -= span.size;
 
637
          n_spans++;
 
638
        }
 
639
      else if (span.size - size_to_fill <= max_waste)
 
640
        {
 
641
          /* Yes and waste is small enough */
 
642
          span.waste = span.size - size_to_fill;
 
643
          if (out_spans)
 
644
            g_array_append_val (out_spans, span);
 
645
 
 
646
          return ++n_spans;
 
647
        }
 
648
      else
 
649
        {
 
650
          /* Yes but waste is too large */
 
651
          while (span.size - size_to_fill > max_waste)
 
652
            {
 
653
              span.size /= 2;
 
654
              g_assert (span.size > 0);
 
655
            }
 
656
        }
 
657
    }
 
658
 
 
659
  /* Can't get here */
 
660
  return 0;
 
661
}
 
662
 
 
663
static void
 
664
_cogl_texture_2d_sliced_set_wrap_mode_parameter (CoglTexture *tex,
 
665
                                                 GLenum wrap_mode)
 
666
{
 
667
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
668
 
 
669
  /* Only set the wrap mode if it's different from the current
 
670
     value to avoid too many GL calls */
 
671
  if (tex_2ds->wrap_mode != wrap_mode)
 
672
    {
 
673
      int i;
 
674
 
 
675
      /* Any queued texture rectangles may be depending on the previous
 
676
       * wrap mode... */
 
677
      _cogl_journal_flush ();
 
678
 
 
679
      for (i = 0; i < tex_2ds->slice_gl_handles->len; i++)
 
680
        {
 
681
          GLuint texnum = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
 
682
 
 
683
          GE( glBindTexture (tex_2ds->gl_target, texnum) );
 
684
          GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_WRAP_S, wrap_mode) );
 
685
          GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_WRAP_T, wrap_mode) );
 
686
        }
 
687
 
 
688
      tex_2ds->wrap_mode = wrap_mode;
 
689
    }
 
690
}
 
691
 
 
692
static gboolean
 
693
_cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
 
694
                                       int width, int height,
 
695
                                       GLenum gl_intformat,
 
696
                                       GLenum gl_format,
 
697
                                       GLenum gl_type)
 
698
{
 
699
  int       max_width;
 
700
  int       max_height;
 
701
  GLuint   *gl_handles;
 
702
  int       n_x_slices;
 
703
  int       n_y_slices;
 
704
  int       n_slices;
 
705
  int       x, y;
 
706
  CoglSpan *x_span;
 
707
  CoglSpan *y_span;
 
708
  const GLfloat transparent_color[4] = { 0x00, 0x00, 0x00, 0x00 };
 
709
 
 
710
  int   (*slices_for_size) (int, int, int, GArray*);
 
711
 
 
712
  /* Initialize size of largest slice according to supported features */
 
713
  if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
 
714
    {
 
715
      max_width = width;
 
716
      max_height = height;
 
717
      tex_2ds->gl_target  = GL_TEXTURE_2D;
 
718
      slices_for_size = _cogl_rect_slices_for_size;
 
719
    }
 
720
  else
 
721
    {
 
722
      max_width = cogl_util_next_p2 (width);
 
723
      max_height = cogl_util_next_p2 (height);
 
724
      tex_2ds->gl_target = GL_TEXTURE_2D;
 
725
      slices_for_size = _cogl_pot_slices_for_size;
 
726
    }
 
727
 
 
728
  /* Negative number means no slicing forced by the user */
 
729
  if (tex_2ds->max_waste <= -1)
 
730
    {
 
731
      CoglSpan span;
 
732
 
 
733
      /* Check if size supported else bail out */
 
734
      if (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
 
735
                                                gl_intformat,
 
736
                                                gl_type,
 
737
                                                max_width,
 
738
                                                max_height))
 
739
        {
 
740
          return FALSE;
 
741
        }
 
742
 
 
743
      n_x_slices = 1;
 
744
      n_y_slices = 1;
 
745
 
 
746
      /* Init span arrays */
 
747
      tex_2ds->slice_x_spans = g_array_sized_new (FALSE, FALSE,
 
748
                                                  sizeof (CoglSpan),
 
749
                                                  1);
 
750
 
 
751
      tex_2ds->slice_y_spans = g_array_sized_new (FALSE, FALSE,
 
752
                                                  sizeof (CoglSpan),
 
753
                                                  1);
 
754
 
 
755
      /* Add a single span for width and height */
 
756
      span.start = 0;
 
757
      span.size = max_width;
 
758
      span.waste = max_width - width;
 
759
      g_array_append_val (tex_2ds->slice_x_spans, span);
 
760
 
 
761
      span.size = max_height;
 
762
      span.waste = max_height - height;
 
763
      g_array_append_val (tex_2ds->slice_y_spans, span);
 
764
    }
 
765
  else
 
766
    {
 
767
      /* Decrease the size of largest slice until supported by GL */
 
768
      while (!_cogl_texture_driver_size_supported (tex_2ds->gl_target,
 
769
                                                   gl_intformat,
 
770
                                                   gl_type,
 
771
                                                   max_width,
 
772
                                                   max_height))
 
773
        {
 
774
          /* Alternate between width and height */
 
775
          if (max_width > max_height)
 
776
            max_width /= 2;
 
777
          else
 
778
            max_height /= 2;
 
779
 
 
780
          if (max_width == 0 || max_height == 0)
 
781
            return FALSE;
 
782
        }
 
783
 
 
784
      /* Determine the slices required to cover the bitmap area */
 
785
      n_x_slices = slices_for_size (width,
 
786
                                    max_width, tex_2ds->max_waste,
 
787
                                    NULL);
 
788
 
 
789
      n_y_slices = slices_for_size (height,
 
790
                                    max_height, tex_2ds->max_waste,
 
791
                                    NULL);
 
792
 
 
793
      /* Init span arrays with reserved size */
 
794
      tex_2ds->slice_x_spans = g_array_sized_new (FALSE, FALSE,
 
795
                                                  sizeof (CoglSpan),
 
796
                                                  n_x_slices);
 
797
 
 
798
      tex_2ds->slice_y_spans = g_array_sized_new (FALSE, FALSE,
 
799
                                                  sizeof (CoglSpan),
 
800
                                                  n_y_slices);
 
801
 
 
802
      /* Fill span arrays with info */
 
803
      slices_for_size (width,
 
804
                       max_width, tex_2ds->max_waste,
 
805
                       tex_2ds->slice_x_spans);
 
806
 
 
807
      slices_for_size (height,
 
808
                       max_height, tex_2ds->max_waste,
 
809
                       tex_2ds->slice_y_spans);
 
810
    }
 
811
 
 
812
  /* Init and resize GL handle array */
 
813
  n_slices = n_x_slices * n_y_slices;
 
814
 
 
815
  tex_2ds->slice_gl_handles = g_array_sized_new (FALSE, FALSE,
 
816
                                                 sizeof (GLuint),
 
817
                                                 n_slices);
 
818
 
 
819
  g_array_set_size (tex_2ds->slice_gl_handles, n_slices);
 
820
 
 
821
  /* Allocate some space to store a copy of the first pixel of each
 
822
     slice. This is only needed if glGenerateMipmap (which is part of
 
823
     the FBO extension) is not available */
 
824
  if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
 
825
    tex_2ds->first_pixels = NULL;
 
826
  else
 
827
    tex_2ds->first_pixels = g_new (CoglTexturePixel, n_slices);
 
828
 
 
829
  /* Wrap mode not yet set */
 
830
  tex_2ds->wrap_mode = GL_FALSE;
 
831
 
 
832
  /* Generate a "working set" of GL texture objects
 
833
   * (some implementations might supported faster
 
834
   *  re-binding between textures inside a set) */
 
835
  gl_handles = (GLuint*) tex_2ds->slice_gl_handles->data;
 
836
 
 
837
  _cogl_texture_driver_gen (GL_TEXTURE_2D, n_slices, gl_handles);
 
838
 
 
839
  /* Init each GL texture object */
 
840
  for (y = 0; y < n_y_slices; ++y)
 
841
    {
 
842
      y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y);
 
843
 
 
844
      for (x = 0; x < n_x_slices; ++x)
 
845
        {
 
846
          x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x);
 
847
 
 
848
          COGL_NOTE (SLICING, "CREATE SLICE (%d,%d)\tsize (%d,%d)",
 
849
                     x, y,
 
850
                     x_span->size - x_span->waste,
 
851
                     y_span->size - y_span->waste);
 
852
 
 
853
          /* Setup texture parameters */
 
854
          GE( glBindTexture (tex_2ds->gl_target,
 
855
                             gl_handles[y * n_x_slices + x] ) );
 
856
 
 
857
          _cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target,
 
858
                                                            transparent_color);
 
859
 
 
860
          /* Pass NULL data to init size and internal format */
 
861
          GE( glTexImage2D (tex_2ds->gl_target, 0, gl_intformat,
 
862
                            x_span->size, y_span->size, 0,
 
863
                            gl_format, gl_type, 0) );
 
864
        }
 
865
    }
 
866
 
 
867
  return TRUE;
 
868
}
 
869
 
 
870
static void
 
871
_cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
 
872
{
 
873
  if (tex_2ds->slice_x_spans != NULL)
 
874
    g_array_free (tex_2ds->slice_x_spans, TRUE);
 
875
 
 
876
  if (tex_2ds->slice_y_spans != NULL)
 
877
    g_array_free (tex_2ds->slice_y_spans, TRUE);
 
878
 
 
879
  if (tex_2ds->slice_gl_handles != NULL)
 
880
    {
 
881
      if (tex_2ds->is_foreign == FALSE)
 
882
        {
 
883
          GE( glDeleteTextures (tex_2ds->slice_gl_handles->len,
 
884
                                (GLuint*) tex_2ds->slice_gl_handles->data) );
 
885
        }
 
886
 
 
887
      g_array_free (tex_2ds->slice_gl_handles, TRUE);
 
888
    }
 
889
 
 
890
  if (tex_2ds->first_pixels != NULL)
 
891
    g_free (tex_2ds->first_pixels);
 
892
}
 
893
 
 
894
static void
 
895
_cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
 
896
{
 
897
  _cogl_texture_2d_sliced_slices_free (tex_2ds);
 
898
  g_free (tex_2ds);
 
899
}
 
900
 
 
901
static gboolean
 
902
_cogl_texture_2d_sliced_upload_from_data
 
903
                                      (CoglTexture2DSliced *tex_2ds,
 
904
                                       CoglBitmap          *bmp,
 
905
                                       CoglPixelFormat      internal_format)
 
906
{
 
907
  CoglTexture *tex = COGL_TEXTURE (tex_2ds);
 
908
  GLenum gl_intformat;
 
909
  GLenum gl_format;
 
910
  GLenum gl_type;
 
911
 
 
912
  tex->vtable = &cogl_texture_2d_sliced_vtable;
 
913
 
 
914
  tex_2ds->is_foreign = FALSE;
 
915
  tex_2ds->auto_mipmap = FALSE;
 
916
  tex_2ds->mipmaps_dirty = TRUE;
 
917
  tex_2ds->first_pixels = NULL;
 
918
 
 
919
  tex_2ds->slice_x_spans = NULL;
 
920
  tex_2ds->slice_y_spans = NULL;
 
921
  tex_2ds->slice_gl_handles = NULL;
 
922
 
 
923
  /* We default to GL_LINEAR for both filters */
 
924
  tex_2ds->min_filter = GL_LINEAR;
 
925
  tex_2ds->mag_filter = GL_LINEAR;
 
926
 
 
927
  if (bmp->data)
 
928
    {
 
929
      CoglBitmap dst_bmp;
 
930
      gboolean dst_bmp_owner;
 
931
 
 
932
      if (!_cogl_texture_prepare_for_upload (bmp,
 
933
                                             internal_format,
 
934
                                             &internal_format,
 
935
                                             &dst_bmp,
 
936
                                             &dst_bmp_owner,
 
937
                                             &gl_intformat,
 
938
                                             &gl_format,
 
939
                                             &gl_type))
 
940
        return FALSE;
 
941
 
 
942
      /* Create slices for the given format and size */
 
943
      if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
 
944
                                                  bmp->width,
 
945
                                                  bmp->height,
 
946
                                                  gl_intformat,
 
947
                                                  gl_format,
 
948
                                                  gl_type))
 
949
        {
 
950
          if (dst_bmp_owner)
 
951
            g_free (dst_bmp.data);
 
952
 
 
953
          return FALSE;
 
954
        }
 
955
 
 
956
      if (!_cogl_texture_2d_sliced_upload_to_gl (tex_2ds,
 
957
                                                 bmp,
 
958
                                                 gl_intformat,
 
959
                                                 gl_format,
 
960
                                                 gl_type))
 
961
        {
 
962
          if (dst_bmp_owner)
 
963
            g_free (dst_bmp.data);
 
964
 
 
965
          return FALSE;
 
966
        }
 
967
 
 
968
      if (dst_bmp_owner)
 
969
        g_free (dst_bmp.data);
 
970
    }
 
971
  else
 
972
    {
 
973
      /* Find closest GL format match */
 
974
      _cogl_pixel_format_to_gl (internal_format,
 
975
                                &gl_intformat,
 
976
                                &gl_format,
 
977
                                &gl_type);
 
978
 
 
979
      /* Create slices for the given format and size */
 
980
      if (!_cogl_texture_2d_sliced_slices_create (tex_2ds,
 
981
                                                  bmp->width,
 
982
                                                  bmp->height,
 
983
                                                  gl_intformat,
 
984
                                                  gl_format,
 
985
                                                  gl_type))
 
986
        return FALSE;
 
987
    }
 
988
 
 
989
  tex_2ds->gl_format = gl_intformat;
 
990
  tex_2ds->width = bmp->width;
 
991
  tex_2ds->height = bmp->height;
 
992
  tex_2ds->format = bmp->format;
 
993
 
 
994
  return TRUE;
 
995
}
 
996
 
 
997
CoglHandle
 
998
_cogl_texture_2d_sliced_new_with_size (unsigned int     width,
 
999
                                       unsigned int     height,
 
1000
                                       CoglTextureFlags flags,
 
1001
                                       CoglPixelFormat  internal_format)
 
1002
{
 
1003
  CoglTexture2DSliced   *tex_2ds;
 
1004
  CoglBitmap             bmp;
 
1005
 
 
1006
  /* Since no data, we need some internal format */
 
1007
  if (internal_format == COGL_PIXEL_FORMAT_ANY)
 
1008
    internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
 
1009
 
 
1010
  /* Init texture with empty bitmap */
 
1011
  tex_2ds = g_new (CoglTexture2DSliced, 1);
 
1012
 
 
1013
  bmp.width = width;
 
1014
  bmp.height = height;
 
1015
  bmp.data = NULL;
 
1016
 
 
1017
  if ((flags & COGL_TEXTURE_NO_SLICING))
 
1018
    tex_2ds->max_waste = -1;
 
1019
  else
 
1020
    tex_2ds->max_waste = COGL_TEXTURE_MAX_WASTE;
 
1021
 
 
1022
  if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, &bmp,
 
1023
                                                 internal_format))
 
1024
    {
 
1025
      _cogl_texture_2d_sliced_free (tex_2ds);
 
1026
      return COGL_INVALID_HANDLE;
 
1027
    }
 
1028
 
 
1029
  tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
 
1030
 
 
1031
  return _cogl_texture_2d_sliced_handle_new (tex_2ds);
 
1032
}
 
1033
 
 
1034
CoglHandle
 
1035
_cogl_texture_2d_sliced_new_from_bitmap (CoglHandle       bmp_handle,
 
1036
                                         CoglTextureFlags flags,
 
1037
                                         CoglPixelFormat  internal_format)
 
1038
{
 
1039
  CoglTexture2DSliced   *tex_2ds;
 
1040
  CoglBitmap            *bmp = (CoglBitmap *)bmp_handle;
 
1041
 
 
1042
  g_return_val_if_fail (bmp_handle != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
 
1043
 
 
1044
  /* Create new texture and fill with loaded data */
 
1045
  tex_2ds = g_new0 (CoglTexture2DSliced, 1);
 
1046
 
 
1047
  if (flags & COGL_TEXTURE_NO_SLICING)
 
1048
    tex_2ds->max_waste = -1;
 
1049
  else
 
1050
    tex_2ds->max_waste = COGL_TEXTURE_MAX_WASTE;
 
1051
 
 
1052
  /* FIXME: If upload fails we should set some kind of
 
1053
   * error flag but still return texture handle if the
 
1054
   * user decides to destroy another texture and upload
 
1055
   * this one instead (reloading from file is not needed
 
1056
   * in that case). As a rule then, everytime a valid
 
1057
   * CoglHandle is returned, it should also be destroyed
 
1058
   * with cogl_handle_unref at some point! */
 
1059
 
 
1060
  if (!_cogl_texture_2d_sliced_upload_from_data (tex_2ds, bmp,
 
1061
                                                 internal_format))
 
1062
    {
 
1063
      _cogl_texture_2d_sliced_free (tex_2ds);
 
1064
      return COGL_INVALID_HANDLE;
 
1065
    }
 
1066
 
 
1067
  tex_2ds->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
 
1068
 
 
1069
  return _cogl_texture_2d_sliced_handle_new (tex_2ds);
 
1070
}
 
1071
 
 
1072
CoglHandle
 
1073
_cogl_texture_2d_sliced_new_from_foreign (GLuint           gl_handle,
 
1074
                                          GLenum           gl_target,
 
1075
                                          GLuint           width,
 
1076
                                          GLuint           height,
 
1077
                                          GLuint           x_pot_waste,
 
1078
                                          GLuint           y_pot_waste,
 
1079
                                          CoglPixelFormat  format)
 
1080
{
 
1081
  /* NOTE: width, height and internal format are not queriable
 
1082
   * in GLES, hence such a function prototype.
 
1083
   */
 
1084
 
 
1085
  GLenum               gl_error = 0;
 
1086
  GLboolean            gl_istexture;
 
1087
  GLint                gl_compressed = GL_FALSE;
 
1088
  GLint                gl_int_format = 0;
 
1089
  GLint                gl_width = 0;
 
1090
  GLint                gl_height = 0;
 
1091
  GLint                gl_gen_mipmap;
 
1092
  CoglTexture2DSliced *tex_2ds;
 
1093
  CoglTexture         *tex;
 
1094
  CoglSpan             x_span;
 
1095
  CoglSpan             y_span;
 
1096
 
 
1097
  if (!_cogl_texture_driver_allows_foreign_gl_target (gl_target))
 
1098
    return COGL_INVALID_HANDLE;
 
1099
 
 
1100
#if HAVE_COGL_GL
 
1101
  /* It shouldn't be necissary to have waste in this case since
 
1102
   * the texture isn't limited to power of two sizes. */
 
1103
  if (gl_target == GL_TEXTURE_RECTANGLE_ARB &&
 
1104
      (x_pot_waste != 0 || y_pot_waste != 0))
 
1105
    {
 
1106
      g_warning ("You can't create a foreign GL_TEXTURE_RECTANGLE cogl "
 
1107
                 "texture with waste\n");
 
1108
      return COGL_INVALID_HANDLE;
 
1109
    }
 
1110
#endif
 
1111
 
 
1112
  /* Make sure it is a valid GL texture object */
 
1113
  gl_istexture = glIsTexture (gl_handle);
 
1114
  if (gl_istexture == GL_FALSE)
 
1115
    return COGL_INVALID_HANDLE;
 
1116
 
 
1117
  /* Make sure binding succeeds */
 
1118
  while ((gl_error = glGetError ()) != GL_NO_ERROR)
 
1119
    ;
 
1120
  glBindTexture (gl_target, gl_handle);
 
1121
  if (glGetError () != GL_NO_ERROR)
 
1122
    return COGL_INVALID_HANDLE;
 
1123
 
 
1124
  /* Obtain texture parameters
 
1125
     (only level 0 we are interested in) */
 
1126
 
 
1127
#if HAVE_COGL_GL
 
1128
  GE( glGetTexLevelParameteriv (gl_target, 0,
 
1129
                                GL_TEXTURE_COMPRESSED,
 
1130
                                &gl_compressed) );
 
1131
 
 
1132
  GE( glGetTexLevelParameteriv (gl_target, 0,
 
1133
                                GL_TEXTURE_INTERNAL_FORMAT,
 
1134
                                &gl_int_format) );
 
1135
#endif
 
1136
 
 
1137
  /* Note: We always trust the given width and height without querying
 
1138
   * the texture object because the user may be creating a Cogl
 
1139
   * texture for a texture_from_pixmap object where glTexImage2D may
 
1140
   * not have been called and the texture_from_pixmap spec doesn't
 
1141
   * clarify that it is reliable to query back the size from OpenGL.
 
1142
   */
 
1143
  gl_width = width + x_pot_waste;
 
1144
  gl_height = height + y_pot_waste;
 
1145
 
 
1146
  GE( glGetTexParameteriv (gl_target,
 
1147
                           GL_GENERATE_MIPMAP,
 
1148
                           &gl_gen_mipmap) );
 
1149
 
 
1150
  /* Validate width and height */
 
1151
  if (gl_width <= 0 || gl_height <= 0)
 
1152
    return COGL_INVALID_HANDLE;
 
1153
 
 
1154
  /* Validate pot waste */
 
1155
  if (x_pot_waste < 0 || x_pot_waste >= gl_width ||
 
1156
      y_pot_waste < 0 || y_pot_waste >= gl_height)
 
1157
    return COGL_INVALID_HANDLE;
 
1158
 
 
1159
  /* Compressed texture images not supported */
 
1160
  if (gl_compressed == GL_TRUE)
 
1161
    return COGL_INVALID_HANDLE;
 
1162
 
 
1163
  /* Try and match to a cogl format */
 
1164
  if (!_cogl_pixel_format_from_gl_internal (gl_int_format, &format))
 
1165
    return COGL_INVALID_HANDLE;
 
1166
 
 
1167
  /* Create new texture */
 
1168
  tex_2ds = g_new0 (CoglTexture2DSliced, 1);
 
1169
 
 
1170
  tex = COGL_TEXTURE (tex_2ds);
 
1171
  tex->vtable = &cogl_texture_2d_sliced_vtable;
 
1172
 
 
1173
  /* Setup bitmap info */
 
1174
  tex_2ds->is_foreign = TRUE;
 
1175
  tex_2ds->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
 
1176
  tex_2ds->mipmaps_dirty = TRUE;
 
1177
  tex_2ds->first_pixels = NULL;
 
1178
 
 
1179
  tex_2ds->format = format;
 
1180
  tex_2ds->width = gl_width - x_pot_waste;
 
1181
  tex_2ds->height = gl_height - y_pot_waste;
 
1182
  tex_2ds->gl_target = gl_target;
 
1183
  tex_2ds->gl_format = gl_int_format;
 
1184
 
 
1185
  /* Unknown filter */
 
1186
  tex_2ds->min_filter = GL_FALSE;
 
1187
  tex_2ds->mag_filter = GL_FALSE;
 
1188
  tex_2ds->max_waste = 0;
 
1189
 
 
1190
  /* Wrap mode not yet set */
 
1191
  tex_2ds->wrap_mode = GL_FALSE;
 
1192
 
 
1193
  /* Create slice arrays */
 
1194
  tex_2ds->slice_x_spans =
 
1195
    g_array_sized_new (FALSE, FALSE,
 
1196
                       sizeof (CoglSpan), 1);
 
1197
 
 
1198
  tex_2ds->slice_y_spans =
 
1199
    g_array_sized_new (FALSE, FALSE,
 
1200
                       sizeof (CoglSpan), 1);
 
1201
 
 
1202
  tex_2ds->slice_gl_handles =
 
1203
    g_array_sized_new (FALSE, FALSE,
 
1204
                       sizeof (GLuint), 1);
 
1205
 
 
1206
  /* Store info for a single slice */
 
1207
  x_span.start = 0;
 
1208
  x_span.size = gl_width;
 
1209
  x_span.waste = x_pot_waste;
 
1210
  g_array_append_val (tex_2ds->slice_x_spans, x_span);
 
1211
 
 
1212
  y_span.start = 0;
 
1213
  y_span.size = gl_height;
 
1214
  y_span.waste = y_pot_waste;
 
1215
  g_array_append_val (tex_2ds->slice_y_spans, y_span);
 
1216
 
 
1217
  g_array_append_val (tex_2ds->slice_gl_handles, gl_handle);
 
1218
 
 
1219
  tex_2ds->first_pixels = NULL;
 
1220
 
 
1221
  return _cogl_texture_2d_sliced_handle_new (tex_2ds);
 
1222
}
 
1223
 
 
1224
static int
 
1225
_cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex)
 
1226
{
 
1227
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1228
 
 
1229
  return tex_2ds->max_waste;
 
1230
}
 
1231
 
 
1232
static gboolean
 
1233
_cogl_texture_2d_sliced_is_sliced (CoglTexture *tex)
 
1234
{
 
1235
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1236
 
 
1237
  if (tex_2ds->slice_gl_handles == NULL)
 
1238
    return FALSE;
 
1239
 
 
1240
  if (tex_2ds->slice_gl_handles->len <= 1)
 
1241
    return FALSE;
 
1242
 
 
1243
  return TRUE;
 
1244
}
 
1245
 
 
1246
static gboolean
 
1247
_cogl_texture_2d_sliced_can_hardware_repeat (CoglTexture *tex)
 
1248
{
 
1249
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1250
  CoglSpan *x_span;
 
1251
  CoglSpan *y_span;
 
1252
 
 
1253
  x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0);
 
1254
  y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, 0);
 
1255
 
 
1256
#if HAVE_COGL_GL
 
1257
  /* TODO: COGL_TEXTURE_TYPE_2D_RECTANGLE */
 
1258
  if (tex_2ds->gl_target == GL_TEXTURE_RECTANGLE_ARB)
 
1259
    return FALSE;
 
1260
#endif
 
1261
 
 
1262
  return (x_span->waste || y_span->waste) ? FALSE : TRUE;
 
1263
}
 
1264
 
 
1265
static void
 
1266
_cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture *tex,
 
1267
                                                float *s,
 
1268
                                                float *t)
 
1269
{
 
1270
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1271
  CoglSpan *x_span;
 
1272
  CoglSpan *y_span;
 
1273
 
 
1274
  g_assert (!_cogl_texture_2d_sliced_is_sliced (tex));
 
1275
 
 
1276
  /* Don't include the waste in the texture coordinates */
 
1277
  x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0);
 
1278
  y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, 0);
 
1279
 
 
1280
  *s *= tex_2ds->width / (float)x_span->size;
 
1281
  *t *= tex_2ds->height / (float)y_span->size;
 
1282
 
 
1283
#if HAVE_COGL_GL
 
1284
  /* Denormalize texture coordinates for rectangle textures */
 
1285
  if (tex_2ds->gl_target == GL_TEXTURE_RECTANGLE_ARB)
 
1286
    {
 
1287
      *s *= x_span->size;
 
1288
      *t *= y_span->size;
 
1289
    }
 
1290
#endif
 
1291
}
 
1292
 
 
1293
static CoglTransformResult
 
1294
_cogl_texture_2d_sliced_transform_quad_coords_to_gl (CoglTexture *tex,
 
1295
                                                     float *coords)
 
1296
{
 
1297
  gboolean need_repeat = FALSE;
 
1298
  int i;
 
1299
 
 
1300
  /* This is a bit lazy - in the case where the quad lies entirely
 
1301
   * within a single slice we could avoid the fallback. But that
 
1302
   * could likely lead to visual inconsistency if the fallback involves
 
1303
   * dropping layers, so this might be the right thing to do anyways.
 
1304
   */
 
1305
  if (_cogl_texture_2d_sliced_is_sliced (tex))
 
1306
    return COGL_TRANSFORM_SOFTWARE_REPEAT;
 
1307
 
 
1308
  for (i = 0; i < 4; i++)
 
1309
    if (coords[i] < 0.0f || coords[i] > 1.0f)
 
1310
      need_repeat = TRUE;
 
1311
 
 
1312
  if (need_repeat && !_cogl_texture_2d_sliced_can_hardware_repeat (tex))
 
1313
    return COGL_TRANSFORM_SOFTWARE_REPEAT;
 
1314
 
 
1315
  _cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 0, coords + 1);
 
1316
  _cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 2, coords + 3);
 
1317
 
 
1318
  return (need_repeat
 
1319
          ? COGL_TRANSFORM_HARDWARE_REPEAT : COGL_TRANSFORM_NO_REPEAT);
 
1320
}
 
1321
 
 
1322
static gboolean
 
1323
_cogl_texture_2d_sliced_get_gl_texture (CoglTexture *tex,
 
1324
                                        GLuint *out_gl_handle,
 
1325
                                        GLenum *out_gl_target)
 
1326
{
 
1327
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1328
 
 
1329
  if (tex_2ds->slice_gl_handles == NULL)
 
1330
    return FALSE;
 
1331
 
 
1332
  if (tex_2ds->slice_gl_handles->len < 1)
 
1333
    return FALSE;
 
1334
 
 
1335
  if (out_gl_handle != NULL)
 
1336
    *out_gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, 0);
 
1337
 
 
1338
  if (out_gl_target != NULL)
 
1339
    *out_gl_target = tex_2ds->gl_target;
 
1340
 
 
1341
  return TRUE;
 
1342
}
 
1343
 
 
1344
static void
 
1345
_cogl_texture_2d_sliced_set_filters (CoglTexture *tex,
 
1346
                                     GLenum min_filter,
 
1347
                                     GLenum mag_filter)
 
1348
{
 
1349
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1350
  GLuint               gl_handle;
 
1351
  int                  i;
 
1352
 
 
1353
  /* Make sure slices were created */
 
1354
  if (tex_2ds->slice_gl_handles == NULL)
 
1355
    return;
 
1356
 
 
1357
  if (min_filter == tex_2ds->min_filter
 
1358
      && mag_filter == tex_2ds->mag_filter)
 
1359
    return;
 
1360
 
 
1361
  /* Store new values */
 
1362
  tex_2ds->min_filter = min_filter;
 
1363
  tex_2ds->mag_filter = mag_filter;
 
1364
 
 
1365
  /* Apply new filters to every slice */
 
1366
  for (i=0; i<tex_2ds->slice_gl_handles->len; ++i)
 
1367
    {
 
1368
      gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
 
1369
      GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
 
1370
      GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MAG_FILTER,
 
1371
                           tex_2ds->mag_filter) );
 
1372
      GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MIN_FILTER,
 
1373
                           tex_2ds->min_filter) );
 
1374
    }
 
1375
}
 
1376
 
 
1377
static void
 
1378
_cogl_texture_2d_sliced_ensure_mipmaps (CoglTexture *tex)
 
1379
{
 
1380
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1381
  int                  i;
 
1382
 
 
1383
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
1384
 
 
1385
  /* Only update if the mipmaps are dirty */
 
1386
  if (!tex_2ds->auto_mipmap || !tex_2ds->mipmaps_dirty)
 
1387
    return;
 
1388
 
 
1389
  /* Make sure slices were created */
 
1390
  if (tex_2ds->slice_gl_handles == NULL)
 
1391
    return;
 
1392
 
 
1393
  /* Regenerate the mipmaps on every slice */
 
1394
  for (i = 0; i < tex_2ds->slice_gl_handles->len; i++)
 
1395
    {
 
1396
      GLuint gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
 
1397
      GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
 
1398
 
 
1399
      /* glGenerateMipmap is defined in the FBO extension */
 
1400
      if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
 
1401
        _cogl_texture_driver_gl_generate_mipmaps (tex_2ds->gl_target);
 
1402
      else if (tex_2ds->first_pixels)
 
1403
        {
 
1404
          CoglTexturePixel *pixel = tex_2ds->first_pixels + i;
 
1405
          /* Temporarily enable automatic mipmap generation and
 
1406
             re-upload the first pixel to cause a regeneration */
 
1407
          GE( glTexParameteri (tex_2ds->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) );
 
1408
          GE( glTexSubImage2D (tex_2ds->gl_target, 0, 0, 0, 1, 1,
 
1409
                               pixel->gl_format, pixel->gl_type,
 
1410
                               pixel->data) );
 
1411
          GE( glTexParameteri (tex_2ds->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) );
 
1412
        }
 
1413
    }
 
1414
 
 
1415
  tex_2ds->mipmaps_dirty = FALSE;
 
1416
}
 
1417
 
 
1418
static void
 
1419
_cogl_texture_2d_sliced_ensure_non_quad_rendering (CoglTexture *tex)
 
1420
{
 
1421
  /* Nothing needs to be done */
 
1422
}
 
1423
 
 
1424
static gboolean
 
1425
_cogl_texture_2d_sliced_set_region (CoglTexture    *tex,
 
1426
                                    int             src_x,
 
1427
                                    int             src_y,
 
1428
                                    int             dst_x,
 
1429
                                    int             dst_y,
 
1430
                                    unsigned int    dst_width,
 
1431
                                    unsigned int    dst_height,
 
1432
                                    int             width,
 
1433
                                    int             height,
 
1434
                                    CoglPixelFormat format,
 
1435
                                    unsigned int    rowstride,
 
1436
                                    const guint8   *data)
 
1437
{
 
1438
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1439
  int                  bpp;
 
1440
  CoglBitmap           source_bmp;
 
1441
  CoglBitmap           tmp_bmp;
 
1442
  gboolean             tmp_bmp_owner = FALSE;
 
1443
  GLenum               closest_gl_format;
 
1444
  GLenum               closest_gl_type;
 
1445
 
 
1446
  /* Check for valid format */
 
1447
  if (format == COGL_PIXEL_FORMAT_ANY)
 
1448
    return FALSE;
 
1449
 
 
1450
  /* Shortcut out early if the image is empty */
 
1451
  if (width == 0 || height == 0)
 
1452
    return TRUE;
 
1453
 
 
1454
  /* Init source bitmap */
 
1455
  source_bmp.width = width;
 
1456
  source_bmp.height = height;
 
1457
  source_bmp.format = format;
 
1458
  source_bmp.data = (guint8 *)data;
 
1459
 
 
1460
  /* Rowstride from width if none specified */
 
1461
  bpp = _cogl_get_format_bpp (format);
 
1462
  source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
 
1463
 
 
1464
  /* Prepare the bitmap so that it will do the premultiplication
 
1465
     conversion */
 
1466
  _cogl_texture_prepare_for_upload (&source_bmp,
 
1467
                                    tex_2ds->format,
 
1468
                                    NULL,
 
1469
                                    &tmp_bmp,
 
1470
                                    &tmp_bmp_owner,
 
1471
                                    NULL,
 
1472
                                    &closest_gl_format,
 
1473
                                    &closest_gl_type);
 
1474
 
 
1475
 
 
1476
  /* Send data to GL */
 
1477
  _cogl_texture_2d_sliced_upload_subregion_to_gl (tex_2ds,
 
1478
                                                  src_x, src_y,
 
1479
                                                  dst_x, dst_y,
 
1480
                                                  dst_width, dst_height,
 
1481
                                                  &tmp_bmp,
 
1482
                                                  closest_gl_format,
 
1483
                                                  closest_gl_type);
 
1484
 
 
1485
  /* Free data if owner */
 
1486
  if (tmp_bmp_owner)
 
1487
    g_free (tmp_bmp.data);
 
1488
 
 
1489
  return TRUE;
 
1490
}
 
1491
 
 
1492
static gboolean
 
1493
_cogl_texture_2d_sliced_download_from_gl (
 
1494
                                      CoglTexture2DSliced *tex_2ds,
 
1495
                                      CoglBitmap          *target_bmp,
 
1496
                                      GLuint               target_gl_format,
 
1497
                                      GLuint               target_gl_type)
 
1498
{
 
1499
  CoglSpan  *x_span;
 
1500
  CoglSpan  *y_span;
 
1501
  GLuint     gl_handle;
 
1502
  int        bpp;
 
1503
  int        x, y;
 
1504
  CoglBitmap slice_bmp;
 
1505
 
 
1506
  bpp = _cogl_get_format_bpp (target_bmp->format);
 
1507
 
 
1508
  /* Iterate vertical slices */
 
1509
  for (y = 0; y < tex_2ds->slice_y_spans->len; ++y)
 
1510
    {
 
1511
      y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y);
 
1512
 
 
1513
      /* Iterate horizontal slices */
 
1514
      for (x = 0; x < tex_2ds->slice_x_spans->len; ++x)
 
1515
        {
 
1516
          /*if (x != 0 || y != 1) continue;*/
 
1517
          x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x);
 
1518
 
 
1519
          /* Pick the gl texture object handle */
 
1520
          gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint,
 
1521
                                     y * tex_2ds->slice_x_spans->len + x);
 
1522
 
 
1523
          /* If there's any waste we need to copy manually
 
1524
             (no glGetTexSubImage) */
 
1525
 
 
1526
          if (y_span->waste != 0 || x_span->waste != 0)
 
1527
            {
 
1528
              /* Setup temp bitmap for slice subregion */
 
1529
              slice_bmp.format = target_bmp->format;
 
1530
              slice_bmp.width  = x_span->size;
 
1531
              slice_bmp.height = y_span->size;
 
1532
              slice_bmp.rowstride = bpp * slice_bmp.width;
 
1533
              slice_bmp.data = g_malloc (slice_bmp.rowstride *
 
1534
                                         slice_bmp.height);
 
1535
 
 
1536
              /* Setup gl alignment to 0,0 top-left corner */
 
1537
              _cogl_texture_driver_prep_gl_for_pixels_download (
 
1538
                                                          slice_bmp.rowstride,
 
1539
                                                          bpp);
 
1540
 
 
1541
              /* Download slice image data into temp bmp */
 
1542
              GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
 
1543
 
 
1544
              if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
 
1545
                                                          target_gl_format,
 
1546
                                                          target_gl_type,
 
1547
                                                          slice_bmp.data))
 
1548
                {
 
1549
                  /* Free temp bitmap */
 
1550
                  g_free (slice_bmp.data);
 
1551
                  return FALSE;
 
1552
                }
 
1553
 
 
1554
              /* Copy portion of slice from temp to target bmp */
 
1555
              _cogl_bitmap_copy_subregion (&slice_bmp,
 
1556
                                           target_bmp,
 
1557
                                           0, 0,
 
1558
                                           x_span->start,
 
1559
                                           y_span->start,
 
1560
                                           x_span->size - x_span->waste,
 
1561
                                           y_span->size - y_span->waste);
 
1562
              /* Free temp bitmap */
 
1563
              g_free (slice_bmp.data);
 
1564
            }
 
1565
          else
 
1566
            {
 
1567
              GLvoid *dst = target_bmp->data
 
1568
                            + x_span->start * bpp
 
1569
                            + y_span->start * target_bmp->rowstride;
 
1570
 
 
1571
              _cogl_texture_driver_prep_gl_for_pixels_download (
 
1572
                                                        target_bmp->rowstride,
 
1573
                                                        bpp);
 
1574
 
 
1575
              /* Download slice image data */
 
1576
              GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
 
1577
 
 
1578
              if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
 
1579
                                                          target_gl_format,
 
1580
                                                          target_gl_type,
 
1581
                                                          dst))
 
1582
                {
 
1583
                  return FALSE;
 
1584
                }
 
1585
            }
 
1586
        }
 
1587
    }
 
1588
 
 
1589
  return TRUE;
 
1590
}
 
1591
 
 
1592
static int
 
1593
_cogl_texture_2d_sliced_get_data (CoglTexture     *tex,
 
1594
                                  CoglPixelFormat  format,
 
1595
                                  unsigned int     rowstride,
 
1596
                                  guint8          *data)
 
1597
{
 
1598
  CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex);
 
1599
  int             bpp;
 
1600
  int             byte_size;
 
1601
  CoglPixelFormat closest_format;
 
1602
  int             closest_bpp;
 
1603
  GLenum          closest_gl_format;
 
1604
  GLenum          closest_gl_type;
 
1605
  CoglBitmap      target_bmp;
 
1606
  CoglBitmap      new_bmp;
 
1607
  gboolean        success;
 
1608
  guint8         *src;
 
1609
  guint8         *dst;
 
1610
  int             y;
 
1611
 
 
1612
  /* Default to internal format if none specified */
 
1613
  if (format == COGL_PIXEL_FORMAT_ANY)
 
1614
    format = tex_2ds->format;
 
1615
 
 
1616
  /* Rowstride from texture width if none specified */
 
1617
  bpp = _cogl_get_format_bpp (format);
 
1618
  if (rowstride == 0)
 
1619
    rowstride = tex_2ds->width * bpp;
 
1620
 
 
1621
  /* Return byte size if only that requested */
 
1622
  byte_size =  tex_2ds->height * rowstride;
 
1623
  if (data == NULL)
 
1624
    return byte_size;
 
1625
 
 
1626
  closest_format =
 
1627
    _cogl_texture_driver_find_best_gl_get_data_format (format,
 
1628
                                                       &closest_gl_format,
 
1629
                                                       &closest_gl_type);
 
1630
  closest_bpp = _cogl_get_format_bpp (closest_format);
 
1631
 
 
1632
  target_bmp.width = tex_2ds->width;
 
1633
  target_bmp.height = tex_2ds->height;
 
1634
 
 
1635
  /* Is the requested format supported? */
 
1636
  if (closest_format == format)
 
1637
    {
 
1638
      /* Target user data directly */
 
1639
      target_bmp.format = format;
 
1640
      target_bmp.rowstride = rowstride;
 
1641
      target_bmp.data = data;
 
1642
    }
 
1643
  else
 
1644
    {
 
1645
      /* Target intermediate buffer */
 
1646
      target_bmp.format = closest_format;
 
1647
      target_bmp.rowstride = target_bmp.width * closest_bpp;
 
1648
      target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride);
 
1649
    }
 
1650
 
 
1651
  /* Retrieve data from slices */
 
1652
  if (!_cogl_texture_2d_sliced_download_from_gl (tex_2ds, &target_bmp,
 
1653
                                                 closest_gl_format,
 
1654
                                                 closest_gl_type))
 
1655
    {
 
1656
      /* XXX: In some cases _cogl_texture_2d_sliced_download_from_gl may
 
1657
       * fail to read back the texture data; such as for GLES which doesn't
 
1658
       * support glGetTexImage, so here we fallback to drawing the texture
 
1659
       * and reading the pixels from the framebuffer. */
 
1660
      _cogl_texture_draw_and_read (tex, &target_bmp,
 
1661
                                   closest_gl_format,
 
1662
                                   closest_gl_type);
 
1663
    }
 
1664
 
 
1665
  /* Was intermediate used? */
 
1666
  if (closest_format != format)
 
1667
    {
 
1668
      /* Convert to requested format */
 
1669
      success = _cogl_bitmap_convert_format_and_premult (&target_bmp,
 
1670
                                                         &new_bmp,
 
1671
                                                         format);
 
1672
 
 
1673
      /* Free intermediate data and return if failed */
 
1674
      g_free (target_bmp.data);
 
1675
      if (!success) return 0;
 
1676
 
 
1677
      /* Copy to user buffer */
 
1678
      for (y = 0; y < new_bmp.height; ++y)
 
1679
        {
 
1680
          src = new_bmp.data + y * new_bmp.rowstride;
 
1681
          dst = data + y * rowstride;
 
1682
          memcpy (dst, src, new_bmp.width);
 
1683
        }
 
1684
 
 
1685
      /* Free converted data */
 
1686
      g_free (new_bmp.data);
 
1687
    }
 
1688
 
 
1689
  return byte_size;
 
1690
}
 
1691
 
 
1692
static CoglPixelFormat
 
1693
_cogl_texture_2d_sliced_get_format (CoglTexture *tex)
 
1694
{
 
1695
  return COGL_TEXTURE_2D_SLICED (tex)->format;
 
1696
}
 
1697
 
 
1698
static GLenum
 
1699
_cogl_texture_2d_sliced_get_gl_format (CoglTexture *tex)
 
1700
{
 
1701
  return COGL_TEXTURE_2D_SLICED (tex)->gl_format;
 
1702
}
 
1703
 
 
1704
static int
 
1705
_cogl_texture_2d_sliced_get_width (CoglTexture *tex)
 
1706
{
 
1707
  return COGL_TEXTURE_2D_SLICED (tex)->width;
 
1708
}
 
1709
 
 
1710
static int
 
1711
_cogl_texture_2d_sliced_get_height (CoglTexture *tex)
 
1712
{
 
1713
  return COGL_TEXTURE_2D_SLICED (tex)->height;
 
1714
}
 
1715
 
 
1716
static const CoglTextureVtable
 
1717
cogl_texture_2d_sliced_vtable =
 
1718
  {
 
1719
    _cogl_texture_2d_sliced_set_region,
 
1720
    _cogl_texture_2d_sliced_get_data,
 
1721
    _cogl_texture_2d_sliced_foreach_sub_texture_in_region,
 
1722
    _cogl_texture_2d_sliced_get_max_waste,
 
1723
    _cogl_texture_2d_sliced_is_sliced,
 
1724
    _cogl_texture_2d_sliced_can_hardware_repeat,
 
1725
    _cogl_texture_2d_sliced_transform_coords_to_gl,
 
1726
    _cogl_texture_2d_sliced_transform_quad_coords_to_gl,
 
1727
    _cogl_texture_2d_sliced_get_gl_texture,
 
1728
    _cogl_texture_2d_sliced_set_filters,
 
1729
    _cogl_texture_2d_sliced_ensure_mipmaps,
 
1730
    _cogl_texture_2d_sliced_ensure_non_quad_rendering,
 
1731
    _cogl_texture_2d_sliced_set_wrap_mode_parameter,
 
1732
    _cogl_texture_2d_sliced_get_format,
 
1733
    _cogl_texture_2d_sliced_get_gl_format,
 
1734
    _cogl_texture_2d_sliced_get_width,
 
1735
    _cogl_texture_2d_sliced_get_height
 
1736
  };