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

« back to all changes in this revision

Viewing changes to clutter/cogl/common/cogl-primitives.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, write to the
20
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
 
 * Boston, MA 02111-1307, USA.
22
 
 */
23
 
 
24
 
#ifdef HAVE_CONFIG_H
25
 
#include "config.h"
26
 
#endif
27
 
 
28
 
#include "cogl.h"
29
 
#include "cogl-internal.h"
30
 
#include "cogl-context.h"
31
 
#include "cogl-texture-private.h"
32
 
#include "cogl-material-private.h"
33
 
#include "cogl-vertex-buffer-private.h"
34
 
 
35
 
#include <string.h>
36
 
#include <gmodule.h>
37
 
#include <math.h>
38
 
 
39
 
#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
40
 
 
41
 
#ifdef HAVE_COGL_GL
42
 
 
43
 
#define glGenBuffers ctx->pf_glGenBuffersARB
44
 
#define glBindBuffer ctx->pf_glBindBufferARB
45
 
#define glBufferData ctx->pf_glBufferDataARB
46
 
#define glBufferSubData ctx->pf_glBufferSubDataARB
47
 
#define glDeleteBuffers ctx->pf_glDeleteBuffersARB
48
 
#define glClientActiveTexture ctx->pf_glClientActiveTexture
49
 
 
50
 
#elif defined (HAVE_COGL_GLES2)
51
 
 
52
 
#include "../gles/cogl-gles2-wrapper.h"
53
 
 
54
 
#endif
55
 
 
56
 
 
57
 
/* XXX NB:
58
 
 * Our journal's vertex data is arranged as follows:
59
 
 * 4 vertices per quad:
60
 
 *    2 or 3 GLfloats per position (3 when doing software transforms)
61
 
 *    4 RGBA GLubytes,
62
 
 *    2 GLfloats per tex coord * n_layers
63
 
 *
64
 
 * Where n_layers corresponds to the number of material layers enabled
65
 
 *
66
 
 * To avoid frequent changes in the stride of our vertex data we always pad
67
 
 * n_layers to be >= 2
68
 
 *
69
 
 * When we are transforming quads in software we need to also track the z
70
 
 * coordinate of transformed vertices.
71
 
 *
72
 
 * So for a given number of layers this gets the stride in 32bit words:
73
 
 */
74
 
#define SW_TRANSFORM      (!(cogl_debug_flags & \
75
 
                             COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
76
 
#define POS_STRIDE        (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */
77
 
#define N_POS_COMPONENTS  POS_STRIDE
78
 
#define COLOR_STRIDE      1 /* number of 32bit words */
79
 
#define TEX_STRIDE        2 /* number of 32bit words */
80
 
#define MIN_LAYER_PADING  2
81
 
#define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
82
 
  (POS_STRIDE + COLOR_STRIDE + \
83
 
   TEX_STRIDE * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS))
84
 
 
85
 
 
86
 
typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
87
 
                                          int n_entries,
88
 
                                          void *data);
89
 
typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
90
 
                                          CoglJournalEntry *entry1);
91
 
typedef CoglVertexBufferIndices  CoglJournalIndices;
92
 
 
93
 
typedef struct _CoglJournalFlushState
94
 
{
95
 
  size_t              stride;
96
 
  /* Note: this is a pointer to handle fallbacks. It normally holds a VBO
97
 
   * offset, but when the driver doesn't support VBOs then this points into
98
 
   * our GArray of logged vertices. */
99
 
  char *                   vbo_offset;
100
 
  GLuint                   vertex_offset;
101
 
#ifndef HAVE_COGL_GL
102
 
  CoglJournalIndices *indices;
103
 
  size_t              indices_type_size;
104
 
#endif
105
 
} CoglJournalFlushState;
106
 
 
107
 
/* these are defined in the particular backend */
108
 
void _cogl_path_add_node    (gboolean new_sub_path,
109
 
                             float x,
110
 
                             float y);
111
 
void _cogl_path_fill_nodes    ();
112
 
void _cogl_path_stroke_nodes  ();
113
 
 
114
 
void
115
 
_cogl_journal_dump_quad_vertices (guint8 *data, int n_layers)
116
 
{
117
 
  size_t stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
118
 
  int i;
119
 
 
120
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
121
 
 
122
 
  g_print ("n_layers = %d; stride = %d; pos stride = %d; color stride = %d; "
123
 
           "tex stride = %d; stride in bytes = %d\n",
124
 
           n_layers, (int)stride, POS_STRIDE, COLOR_STRIDE,
125
 
           TEX_STRIDE, (int)stride * 4);
126
 
 
127
 
  for (i = 0; i < 4; i++)
128
 
    {
129
 
      float *v = (float *)data + (i * stride);
130
 
      guint8 *c = data + (POS_STRIDE * 4) + (i * stride * 4);
131
 
      int j;
132
 
 
133
 
      if (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)
134
 
        g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X",
135
 
                 i, v[0], v[1], c[0], c[1], c[2], c[3]);
136
 
      else
137
 
        g_print ("v%d: x = %f, y = %f, z = %f, rgba=0x%02X%02X%02X%02X",
138
 
                 i, v[0], v[1], v[2], c[0], c[1], c[2], c[3]);
139
 
      for (j = 0; j < n_layers; j++)
140
 
        {
141
 
          float *t = v + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * j;
142
 
          g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]);
143
 
        }
144
 
      g_print ("\n");
145
 
    }
146
 
}
147
 
 
148
 
void
149
 
_cogl_journal_dump_quad_batch (guint8 *data, int n_layers, int n_quads)
150
 
{
151
 
  size_t byte_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
152
 
  int i;
153
 
 
154
 
  g_print ("_cogl_journal_dump_quad_batch: n_layers = %d, n_quads = %d\n",
155
 
           n_layers, n_quads);
156
 
  for (i = 0; i < n_quads; i++)
157
 
    _cogl_journal_dump_quad_vertices (data + byte_stride * 4 * i, n_layers);
158
 
}
159
 
 
160
 
static void
161
 
batch_and_call (CoglJournalEntry *entries,
162
 
                int n_entries,
163
 
                CoglJournalBatchTest can_batch_callback,
164
 
                CoglJournalBatchCallback batch_callback,
165
 
                void *data)
166
 
{
167
 
  int i;
168
 
  int batch_len = 1;
169
 
  CoglJournalEntry *batch_start = entries;
170
 
 
171
 
  for (i = 1; i < n_entries; i++)
172
 
    {
173
 
      CoglJournalEntry *entry0 = &entries[i - 1];
174
 
      CoglJournalEntry *entry1 = entry0 + 1;
175
 
 
176
 
      if (can_batch_callback (entry0, entry1))
177
 
        {
178
 
          batch_len++;
179
 
          continue;
180
 
        }
181
 
 
182
 
      batch_callback (batch_start, batch_len, data);
183
 
 
184
 
      batch_start = entry1;
185
 
      batch_len = 1;
186
 
    }
187
 
 
188
 
  /* The last batch... */
189
 
  batch_callback (batch_start, batch_len, data);
190
 
}
191
 
 
192
 
static void
193
 
_cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
194
 
                                           int               batch_len,
195
 
                                           void             *data)
196
 
{
197
 
  CoglJournalFlushState *state = data;
198
 
 
199
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
200
 
    g_print ("BATCHING:    modelview batch len = %d\n", batch_len);
201
 
 
202
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
203
 
    GE (glLoadMatrixf ((GLfloat *)&batch_start->model_view));
204
 
 
205
 
#ifdef HAVE_COGL_GL
206
 
 
207
 
  GE (glDrawArrays (GL_QUADS, state->vertex_offset, batch_len * 4));
208
 
 
209
 
#else /* HAVE_COGL_GL */
210
 
 
211
 
  if (batch_len > 1)
212
 
    {
213
 
      int indices_offset = (state->vertex_offset / 4) * 6;
214
 
      GE (glDrawElements (GL_TRIANGLES,
215
 
                          6 * batch_len,
216
 
                          state->indices->type,
217
 
                          (GLvoid*)(indices_offset * state->indices_type_size)));
218
 
    }
219
 
  else
220
 
    {
221
 
      GE (glDrawArrays (GL_TRIANGLE_FAN,
222
 
                        state->vertex_offset, /* first */
223
 
                        4)); /* n vertices */
224
 
    }
225
 
#endif
226
 
 
227
 
  /* DEBUGGING CODE XXX:
228
 
   * This path will cause all rectangles to be drawn with a red, green
229
 
   * or blue outline with no blending. This may e.g. help with debugging
230
 
   * texture slicing issues or blending issues, plus it looks quite cool.
231
 
   */
232
 
  if (cogl_debug_flags & COGL_DEBUG_RECTANGLES)
233
 
    {
234
 
      static CoglHandle outline = COGL_INVALID_HANDLE;
235
 
      static int color = 0;
236
 
      int i;
237
 
      if (outline == COGL_INVALID_HANDLE)
238
 
        outline = cogl_material_new ();
239
 
 
240
 
      cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
241
 
      for (i = 0; i < batch_len; i++, color = (color + 1) % 3)
242
 
        {
243
 
          cogl_material_set_color4ub (outline,
244
 
                                      color == 0 ? 0xff : 0x00,
245
 
                                      color == 1 ? 0xff : 0x00,
246
 
                                      color == 2 ? 0xff : 0x00,
247
 
                                      0xff);
248
 
          _cogl_material_flush_gl_state (outline, NULL);
249
 
          GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) );
250
 
        }
251
 
    }
252
 
 
253
 
  state->vertex_offset += (4 * batch_len);
254
 
}
255
 
 
256
 
static gboolean
257
 
compare_entry_modelviews (CoglJournalEntry *entry0,
258
 
                          CoglJournalEntry *entry1)
259
 
{
260
 
  /* Batch together quads with the same model view matrix */
261
 
 
262
 
  /* FIXME: this is nasty, there are much nicer ways to track this
263
 
   * (at the add_quad_vertices level) without resorting to a memcmp!
264
 
   *
265
 
   * E.g. If the cogl-current-matrix code maintained an "age" for
266
 
   * the modelview matrix we could simply check in add_quad_vertices
267
 
   * if the age has increased, and if so record the change as a
268
 
   * boolean in the journal.
269
 
   */
270
 
 
271
 
  if (memcmp (&entry0->model_view, &entry1->model_view,
272
 
              sizeof (GLfloat) * 16) == 0)
273
 
    return TRUE;
274
 
  else
275
 
    return FALSE;
276
 
}
277
 
 
278
 
/* At this point we have a run of quads that we know have compatible
279
 
 * materials, but they may not all have the same modelview matrix */
280
 
static void
281
 
_cogl_journal_flush_material_and_entries (CoglJournalEntry *batch_start,
282
 
                                          gint              batch_len,
283
 
                                          void             *data)
284
 
{
285
 
  gulong                 enable_flags = 0;
286
 
 
287
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
288
 
 
289
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
290
 
    g_print ("BATCHING:   material batch len = %d\n", batch_len);
291
 
 
292
 
  _cogl_material_flush_gl_state (batch_start->material,
293
 
                                 &batch_start->flush_options);
294
 
 
295
 
  /* FIXME: This api is a bit yukky, ideally it will be removed if we
296
 
   * re-work the cogl_enable mechanism */
297
 
  enable_flags |= _cogl_material_get_cogl_enable_flags (batch_start->material);
298
 
 
299
 
  if (ctx->enable_backface_culling)
300
 
    enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
301
 
 
302
 
  enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
303
 
  enable_flags |= COGL_ENABLE_COLOR_ARRAY;
304
 
  cogl_enable (enable_flags);
305
 
 
306
 
  /* If we haven't transformed the quads in software then we need to also break
307
 
   * up batches according to changes in the modelview matrix... */
308
 
  if (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)
309
 
    {
310
 
      batch_and_call (batch_start,
311
 
                      batch_len,
312
 
                      compare_entry_modelviews,
313
 
                      _cogl_journal_flush_modelview_and_entries,
314
 
                      data);
315
 
    }
316
 
  else
317
 
    _cogl_journal_flush_modelview_and_entries (batch_start, batch_len, data);
318
 
}
319
 
 
320
 
static gboolean
321
 
compare_entry_materials (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
322
 
{
323
 
  /* batch rectangles using compatible materials */
324
 
 
325
 
  /* XXX: _cogl_material_equal may give false negatives since it avoids
326
 
   * deep comparisons as an optimization. It aims to compare enough so
327
 
   * that we that we are able to batch the 90% common cases, but may not
328
 
   * look at less common differences. */
329
 
  if (_cogl_material_equal (entry0->material,
330
 
                            &entry0->flush_options,
331
 
                            entry1->material,
332
 
                            &entry1->flush_options))
333
 
    return TRUE;
334
 
  else
335
 
    return FALSE;
336
 
}
337
 
 
338
 
/* Since the stride may not reflect the number of texture layers in use
339
 
 * (due to padding) we deal with texture coordinate offsets separately
340
 
 * from vertex and color offsets... */
341
 
static void
342
 
_cogl_journal_flush_texcoord_vbo_offsets_and_entries (
343
 
                                          CoglJournalEntry *batch_start,
344
 
                                          gint              batch_len,
345
 
                                          void             *data)
346
 
{
347
 
  CoglJournalFlushState *state = data;
348
 
  int                    prev_n_texcoord_arrays_enabled;
349
 
  int                    i;
350
 
 
351
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
352
 
 
353
 
  for (i = 0; i < batch_start->n_layers; i++)
354
 
    {
355
 
      GE (glClientActiveTexture (GL_TEXTURE0 + i));
356
 
      GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
357
 
      /* XXX NB:
358
 
       * Our journal's vertex data is arranged as follows:
359
 
       * 4 vertices per quad:
360
 
       *    2 or 3 GLfloats per position (3 when doing software transforms)
361
 
       *    4 RGBA GLubytes,
362
 
       *    2 GLfloats per tex coord * n_layers
363
 
       * (though n_layers may be padded; see definition of
364
 
       *  GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
365
 
       */
366
 
      GE (glTexCoordPointer (2, GL_FLOAT, state->stride,
367
 
                             (void *)(state->vbo_offset +
368
 
                                      (POS_STRIDE + COLOR_STRIDE) * 4 +
369
 
                                      TEX_STRIDE * 4 * i)));
370
 
    }
371
 
  prev_n_texcoord_arrays_enabled =
372
 
    ctx->n_texcoord_arrays_enabled;
373
 
  ctx->n_texcoord_arrays_enabled = batch_start->n_layers;
374
 
  for (; i < prev_n_texcoord_arrays_enabled; i++)
375
 
    {
376
 
      GE (glClientActiveTexture (GL_TEXTURE0 + i));
377
 
      GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
378
 
    }
379
 
 
380
 
  batch_and_call (batch_start,
381
 
                  batch_len,
382
 
                  compare_entry_materials,
383
 
                  _cogl_journal_flush_material_and_entries,
384
 
                  data);
385
 
}
386
 
 
387
 
static gboolean
388
 
compare_entry_n_layers (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
389
 
{
390
 
  if (entry0->n_layers == entry1->n_layers)
391
 
    return TRUE;
392
 
  else
393
 
    return FALSE;
394
 
}
395
 
 
396
 
/* At this point we know the stride has changed from the previous batch
397
 
 * of journal entries */
398
 
static void
399
 
_cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
400
 
                                             gint              batch_len,
401
 
                                             void             *data)
402
 
{
403
 
  CoglJournalFlushState   *state = data;
404
 
  size_t                   stride;
405
 
#ifndef HAVE_COGL_GL
406
 
  int                      needed_indices = batch_len * 6;
407
 
  CoglHandle               indices_handle;
408
 
  CoglVertexBufferIndices *indices;
409
 
#endif
410
 
 
411
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
412
 
 
413
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
414
 
    g_print ("BATCHING:  vbo offset batch len = %d\n", batch_len);
415
 
 
416
 
  /* XXX NB:
417
 
   * Our journal's vertex data is arranged as follows:
418
 
   * 4 vertices per quad:
419
 
   *    2 or 3 GLfloats per position (3 when doing software transforms)
420
 
   *    4 RGBA GLubytes,
421
 
   *    2 GLfloats per tex coord * n_layers
422
 
   * (though n_layers may be padded; see definition of
423
 
   *  GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
424
 
   */
425
 
  stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
426
 
  stride *= sizeof (GLfloat);
427
 
  state->stride = stride;
428
 
 
429
 
  GE (glVertexPointer (N_POS_COMPONENTS, GL_FLOAT, stride,
430
 
                       (void *)state->vbo_offset));
431
 
  GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
432
 
                      (void *)(state->vbo_offset + (POS_STRIDE * 4))));
433
 
 
434
 
#ifndef HAVE_COGL_GL
435
 
  indices_handle = cogl_vertex_buffer_indices_get_for_quads (needed_indices);
436
 
  indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
437
 
  state->indices = indices;
438
 
 
439
 
  if (indices->type == GL_UNSIGNED_BYTE)
440
 
    state->indices_type_size = 1;
441
 
  else if (indices->type == GL_UNSIGNED_SHORT)
442
 
    state->indices_type_size = 2;
443
 
  else
444
 
    g_critical ("unknown indices type %d", indices->type);
445
 
 
446
 
  GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
447
 
                    GPOINTER_TO_UINT (indices->vbo_name)));
448
 
#endif
449
 
 
450
 
  /* We only call gl{Vertex,Color,Texture}Pointer when the stride within
451
 
   * the VBO changes. (due to a change in the number of material layers)
452
 
   * While the stride remains constant we walk forward through the above
453
 
   * VBO using a vertex offset passed to glDraw{Arrays,Elements} */
454
 
  state->vertex_offset = 0;
455
 
 
456
 
  if (cogl_debug_flags & COGL_DEBUG_JOURNAL)
457
 
    {
458
 
      guint8 *verts;
459
 
 
460
 
      if (cogl_get_features () & COGL_FEATURE_VBOS)
461
 
        verts = ((guint8 *)ctx->logged_vertices->data) +
462
 
          (size_t)state->vbo_offset;
463
 
      else
464
 
        verts = (guint8 *)state->vbo_offset;
465
 
      _cogl_journal_dump_quad_batch (verts,
466
 
                                     batch_start->n_layers,
467
 
                                     batch_len);
468
 
    }
469
 
 
470
 
  batch_and_call (batch_start,
471
 
                  batch_len,
472
 
                  compare_entry_n_layers,
473
 
                  _cogl_journal_flush_texcoord_vbo_offsets_and_entries,
474
 
                  data);
475
 
 
476
 
  /* progress forward through the VBO containing all our vertices */
477
 
  state->vbo_offset += (stride * 4 * batch_len);
478
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
479
 
    g_print ("new vbo offset = %lu\n", (gulong)state->vbo_offset);
480
 
}
481
 
 
482
 
static gboolean
483
 
compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
484
 
{
485
 
  /* Currently the only thing that affects the stride for our vertex arrays
486
 
   * is the number of material layers. We need to update our VBO offsets
487
 
   * whenever the stride changes. */
488
 
  /* TODO: We should be padding the n_layers == 1 case as if it were
489
 
   * n_layers == 2 so we can reduce the need to split batches. */
490
 
  if (entry0->n_layers == entry1->n_layers ||
491
 
      (entry0->n_layers <= MIN_LAYER_PADING &&
492
 
       entry1->n_layers <= MIN_LAYER_PADING))
493
 
    return TRUE;
494
 
  else
495
 
    return FALSE;
496
 
}
497
 
 
498
 
static GLuint
499
 
upload_vertices_to_vbo (GArray *vertices, CoglJournalFlushState *state)
500
 
{
501
 
  size_t needed_vbo_len;
502
 
  GLuint journal_vbo;
503
 
 
504
 
  _COGL_GET_CONTEXT (ctx, 0);
505
 
 
506
 
  needed_vbo_len = vertices->len * sizeof (GLfloat);
507
 
 
508
 
  g_assert (needed_vbo_len);
509
 
  GE (glGenBuffers (1, &journal_vbo));
510
 
  GE (glBindBuffer (GL_ARRAY_BUFFER, journal_vbo));
511
 
  GE (glBufferData (GL_ARRAY_BUFFER,
512
 
                    needed_vbo_len,
513
 
                    vertices->data,
514
 
                    GL_STATIC_DRAW));
515
 
 
516
 
  /* As we flush the journal entries in batches we walk forward through the
517
 
   * above VBO starting at offset 0... */
518
 
  state->vbo_offset = 0;
519
 
 
520
 
  return journal_vbo;
521
 
}
522
 
 
523
 
/* XXX NB: When _cogl_journal_flush() returns all state relating
524
 
 * to materials, all glEnable flags and current matrix state
525
 
 * is undefined.
526
 
 */
527
 
void
528
 
_cogl_journal_flush (void)
529
 
{
530
 
  CoglJournalFlushState state;
531
 
  int                   i;
532
 
  GLuint                journal_vbo;
533
 
  gboolean              vbo_fallback =
534
 
    (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
535
 
 
536
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
537
 
 
538
 
  if (ctx->journal->len == 0)
539
 
    return;
540
 
 
541
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
542
 
    g_print ("BATCHING: journal len = %d\n", ctx->journal->len);
543
 
 
544
 
  /* Load all the vertex data we have accumulated so far into a single VBO
545
 
   * to minimize memory management costs within the GL driver. */
546
 
  if (!vbo_fallback)
547
 
    journal_vbo = upload_vertices_to_vbo (ctx->logged_vertices, &state);
548
 
  else
549
 
    state.vbo_offset = (char *)ctx->logged_vertices->data;
550
 
 
551
 
  /* Since the journal deals with emitting the modelview matrices manually
552
 
   * we need to dirty our client side modelview matrix stack cache... */
553
 
  _cogl_current_matrix_state_dirty ();
554
 
 
555
 
  /* And explicitly flush other matrix stacks... */
556
 
  _cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
557
 
  _cogl_current_matrix_state_flush ();
558
 
 
559
 
  /* If we have transformed all our quads at log time then the whole journal
560
 
   * then we ensure no further model transform is applied by loading the
561
 
   * identity matrix here...*/
562
 
  if (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
563
 
    {
564
 
      GE (glMatrixMode (GL_MODELVIEW));
565
 
      glLoadIdentity ();
566
 
    }
567
 
 
568
 
  /* batch_and_call() batches a list of journal entries according to some
569
 
   * given criteria and calls a callback once for each determined batch.
570
 
   *
571
 
   * The process of flushing the journal is staggered to reduce the amount
572
 
   * of driver/GPU state changes necessary:
573
 
   * 1) We split the entries according to the stride of the vertices:
574
 
   *      Each time the stride of our vertex data changes we need to call
575
 
   *      gl{Vertex,Color}Pointer to inform GL of new VBO offsets.
576
 
   *      Currently the only thing that affects the stride of our vertex data
577
 
   *      is the number of material layers.
578
 
   * 2) We split the entries explicitly by the number of material layers:
579
 
   *      We pad our vertex data when the number of layers is < 2 so that we
580
 
   *      can minimize changes in stride. Each time the number of layers
581
 
   *      changes we need to call glTexCoordPointer to inform GL of new VBO
582
 
   *      offsets.
583
 
   * 3) We then split according to compatible Cogl materials:
584
 
   *      This is where we flush material state
585
 
   * 4) Finally we split according to modelview matrix changes:
586
 
   *      This is when we finally tell GL to draw something.
587
 
   *      Note: Splitting by modelview changes is skipped when are doing the
588
 
   *      vertex transformation in software at log time.
589
 
   */
590
 
  batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
591
 
                  ctx->journal->len, /* max number of entries to consider */
592
 
                  compare_entry_strides,
593
 
                  _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
594
 
                  &state); /* data */
595
 
 
596
 
  for (i = 0; i < ctx->journal->len; i++)
597
 
    {
598
 
      CoglJournalEntry *entry =
599
 
        &g_array_index (ctx->journal, CoglJournalEntry, i);
600
 
      _cogl_material_journal_unref (entry->material);
601
 
    }
602
 
 
603
 
  if (!vbo_fallback)
604
 
    GE (glDeleteBuffers (1, &journal_vbo));
605
 
 
606
 
  g_array_set_size (ctx->journal, 0);
607
 
  g_array_set_size (ctx->logged_vertices, 0);
608
 
}
609
 
 
610
 
static void
611
 
_cogl_journal_log_quad (float       x_1,
612
 
                        float       y_1,
613
 
                        float       x_2,
614
 
                        float       y_2,
615
 
                        CoglHandle  material,
616
 
                        int         n_layers,
617
 
                        guint32     fallback_layers,
618
 
                        GLuint      layer0_override_texture,
619
 
                        float      *tex_coords,
620
 
                        guint       tex_coords_len)
621
 
{
622
 
  size_t            stride;
623
 
  size_t            byte_stride;
624
 
  int               next_vert;
625
 
  GLfloat          *v;
626
 
  GLubyte          *c;
627
 
  GLubyte          *src_c;
628
 
  int               i;
629
 
  int               next_entry;
630
 
  guint32           disable_layers;
631
 
  CoglJournalEntry *entry;
632
 
 
633
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
634
 
 
635
 
  /* The vertex data is logged into a separate array in a layout that can be
636
 
   * directly passed to OpenGL
637
 
   */
638
 
 
639
 
  /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
640
 
   * about how we pack our vertex data */
641
 
  stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
642
 
  /* NB: stride is in 32bit words */
643
 
  byte_stride = stride * 4;
644
 
 
645
 
  next_vert = ctx->logged_vertices->len;
646
 
  g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride);
647
 
  v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
648
 
  c = (GLubyte *)(v + POS_STRIDE);
649
 
 
650
 
  /* XXX: All the jumping around to fill in this strided buffer doesn't
651
 
   * seem ideal. */
652
 
 
653
 
  /* XXX: we could defer expanding the vertex data for GL until we come
654
 
   * to flushing the journal. */
655
 
 
656
 
  /* FIXME: This is a hacky optimization, since it will break if we
657
 
   * change the definition of CoglColor: */
658
 
  _cogl_material_get_colorubv (material, c);
659
 
  src_c = c;
660
 
  for (i = 0; i < 3; i++)
661
 
    {
662
 
      c += byte_stride;
663
 
      memcpy (c, src_c, 4);
664
 
    }
665
 
 
666
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
667
 
    {
668
 
      v[0] = x_1; v[1] = y_1;
669
 
      v += stride;
670
 
      v[0] = x_1; v[1] = y_2;
671
 
      v += stride;
672
 
      v[0] = x_2; v[1] = y_2;
673
 
      v += stride;
674
 
      v[0] = x_2; v[1] = y_1;
675
 
    }
676
 
  else
677
 
    {
678
 
      CoglMatrix  mv;
679
 
      float       x, y, z, w;
680
 
 
681
 
      cogl_get_modelview_matrix (&mv);
682
 
 
683
 
      x = x_1, y = y_1, z = 0; w = 1;
684
 
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
685
 
      v[0] = x; v[1] = y; v[2] = z;
686
 
      v += stride;
687
 
      x = x_1, y = y_2, z = 0; w = 1;
688
 
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
689
 
      v[0] = x; v[1] = y; v[2] = z;
690
 
      v += stride;
691
 
      x = x_2, y = y_2, z = 0; w = 1;
692
 
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
693
 
      v[0] = x; v[1] = y; v[2] = z;
694
 
      v += stride;
695
 
      x = x_2, y = y_1, z = 0; w = 1;
696
 
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
697
 
      v[0] = x; v[1] = y; v[2] = z;
698
 
    }
699
 
 
700
 
  for (i = 0; i < n_layers; i++)
701
 
    {
702
 
      /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
703
 
       * about how we pack our vertex data */
704
 
      GLfloat *t = &g_array_index (ctx->logged_vertices, GLfloat,
705
 
                                   next_vert +  POS_STRIDE +
706
 
                                   COLOR_STRIDE + TEX_STRIDE * i);
707
 
 
708
 
      t[0] = tex_coords[0]; t[1] = tex_coords[1];
709
 
      t += stride;
710
 
      t[0] = tex_coords[0]; t[1] = tex_coords[3];
711
 
      t += stride;
712
 
      t[0] = tex_coords[2]; t[1] = tex_coords[3];
713
 
      t += stride;
714
 
      t[0] = tex_coords[2]; t[1] = tex_coords[1];
715
 
    }
716
 
 
717
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
718
 
    {
719
 
      g_print ("Logged new quad:\n");
720
 
      v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
721
 
      _cogl_journal_dump_quad_vertices ((guint8 *)v, n_layers);
722
 
    }
723
 
 
724
 
  next_entry = ctx->journal->len;
725
 
  g_array_set_size (ctx->journal, next_entry + 1);
726
 
  entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry);
727
 
 
728
 
  disable_layers = (1 << n_layers) - 1;
729
 
  disable_layers = ~disable_layers;
730
 
 
731
 
  entry->material = _cogl_material_journal_ref (material);
732
 
  entry->n_layers = n_layers;
733
 
  entry->flush_options.flags =
734
 
    COGL_MATERIAL_FLUSH_FALLBACK_MASK |
735
 
    COGL_MATERIAL_FLUSH_DISABLE_MASK |
736
 
    COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
737
 
  entry->flush_options.fallback_layers = fallback_layers;
738
 
  entry->flush_options.disable_layers = disable_layers;
739
 
  if (layer0_override_texture)
740
 
    {
741
 
      entry->flush_options.flags |= COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
742
 
      entry->flush_options.layer0_override_texture = layer0_override_texture;
743
 
    }
744
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
745
 
    cogl_get_modelview_matrix (&entry->model_view);
746
 
 
747
 
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING
748
 
                  || cogl_debug_flags & COGL_DEBUG_RECTANGLES))
749
 
    _cogl_journal_flush ();
750
 
}
751
 
 
752
 
static void
753
 
_cogl_texture_sliced_quad (CoglTexture *tex,
754
 
                           CoglHandle   material,
755
 
                           float        x_1,
756
 
                           float        y_1,
757
 
                           float        x_2,
758
 
                           float        y_2,
759
 
                           float        tx_1,
760
 
                           float        ty_1,
761
 
                           float        tx_2,
762
 
                           float        ty_2)
763
 
{
764
 
  CoglSpanIter  iter_x    ,  iter_y;
765
 
  float         tw        ,  th;
766
 
  float         tqx       ,  tqy;
767
 
  float         first_tx  ,  first_ty;
768
 
  float         first_qx  ,  first_qy;
769
 
  float         slice_tx1 ,  slice_ty1;
770
 
  float         slice_tx2 ,  slice_ty2;
771
 
  float         slice_qx1 ,  slice_qy1;
772
 
  float         slice_qx2 ,  slice_qy2;
773
 
  GLuint        gl_handle;
774
 
 
775
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
776
 
 
777
 
  COGL_NOTE (DRAW, "Drawing Tex Quad (Sliced Mode)");
778
 
 
779
 
  /* We can't use hardware repeat so we need to set clamp to edge
780
 
     otherwise it might pull in edge pixels from the other side */
781
 
  _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
782
 
 
783
 
  /* If the texture coordinates are backwards then swap both the
784
 
     geometry and texture coordinates so that the texture will be
785
 
     flipped but we can still use the same algorithm to iterate the
786
 
     slices */
787
 
  if (tx_2 < tx_1)
788
 
    {
789
 
      float temp = x_1;
790
 
      x_1 = x_2;
791
 
      x_2 = temp;
792
 
      temp = tx_1;
793
 
      tx_1 = tx_2;
794
 
      tx_2 = temp;
795
 
    }
796
 
  if (ty_2 < ty_1)
797
 
    {
798
 
      float temp = y_1;
799
 
      y_1 = y_2;
800
 
      y_2 = temp;
801
 
      temp = ty_1;
802
 
      ty_1 = ty_2;
803
 
      ty_2 = temp;
804
 
    }
805
 
 
806
 
  /* Scale ratio from texture to quad widths */
807
 
  tw = (float)(tex->bitmap.width);
808
 
  th = (float)(tex->bitmap.height);
809
 
 
810
 
  tqx = (x_2 - x_1) / (tw * (tx_2 - tx_1));
811
 
  tqy = (y_2 - y_1) / (th * (ty_2 - ty_1));
812
 
 
813
 
  /* Integral texture coordinate for first tile */
814
 
  first_tx = (float)(floorf (tx_1));
815
 
  first_ty = (float)(floorf (ty_1));
816
 
 
817
 
  /* Denormalize texture coordinates */
818
 
  first_tx = (first_tx * tw);
819
 
  first_ty = (first_ty * th);
820
 
  tx_1 = (tx_1 * tw);
821
 
  ty_1 = (ty_1 * th);
822
 
  tx_2 = (tx_2 * tw);
823
 
  ty_2 = (ty_2 * th);
824
 
 
825
 
  /* Quad coordinate of the first tile */
826
 
  first_qx = x_1 - (tx_1 - first_tx) * tqx;
827
 
  first_qy = y_1 - (ty_1 - first_ty) * tqy;
828
 
 
829
 
 
830
 
  /* Iterate until whole quad height covered */
831
 
  for (_cogl_span_iter_begin (&iter_y, tex->slice_y_spans,
832
 
                              first_ty, ty_1, ty_2) ;
833
 
       !_cogl_span_iter_end  (&iter_y) ;
834
 
       _cogl_span_iter_next  (&iter_y) )
835
 
    {
836
 
      float tex_coords[4];
837
 
 
838
 
      /* Discard slices out of quad early */
839
 
      if (!iter_y.intersects) continue;
840
 
 
841
 
      /* Span-quad intersection in quad coordinates */
842
 
      slice_qy1 = first_qy + (iter_y.intersect_start - first_ty) * tqy;
843
 
 
844
 
      slice_qy2 = first_qy + (iter_y.intersect_end - first_ty) * tqy;
845
 
 
846
 
      /* Localize slice texture coordinates */
847
 
      slice_ty1 = iter_y.intersect_start - iter_y.pos;
848
 
      slice_ty2 = iter_y.intersect_end - iter_y.pos;
849
 
 
850
 
      /* Normalize texture coordinates to current slice
851
 
         (rectangle texture targets take denormalized) */
852
 
#if HAVE_COGL_GL
853
 
      if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
854
 
#endif
855
 
        {
856
 
          slice_ty1 /= iter_y.span->size;
857
 
          slice_ty2 /= iter_y.span->size;
858
 
        }
859
 
 
860
 
      /* Iterate until whole quad width covered */
861
 
      for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans,
862
 
                                  first_tx, tx_1, tx_2) ;
863
 
           !_cogl_span_iter_end  (&iter_x) ;
864
 
           _cogl_span_iter_next  (&iter_x) )
865
 
        {
866
 
          /* Discard slices out of quad early */
867
 
          if (!iter_x.intersects) continue;
868
 
 
869
 
          /* Span-quad intersection in quad coordinates */
870
 
          slice_qx1 = first_qx + (iter_x.intersect_start - first_tx) * tqx;
871
 
 
872
 
          slice_qx2 = first_qx + (iter_x.intersect_end - first_tx) * tqx;
873
 
 
874
 
          /* Localize slice texture coordinates */
875
 
          slice_tx1 = iter_x.intersect_start - iter_x.pos;
876
 
          slice_tx2 = iter_x.intersect_end - iter_x.pos;
877
 
 
878
 
          /* Normalize texture coordinates to current slice
879
 
             (rectangle texture targets take denormalized) */
880
 
#if HAVE_COGL_GL
881
 
          if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
882
 
#endif
883
 
            {
884
 
              slice_tx1 /= iter_x.span->size;
885
 
              slice_tx2 /= iter_x.span->size;
886
 
            }
887
 
 
888
 
          COGL_NOTE (DRAW,
889
 
                     "~~~~~ slice (%d, %d)\n"
890
 
                     "qx1: %f\t"
891
 
                     "qy1: %f\n"
892
 
                     "qx2: %f\t"
893
 
                     "qy2: %f\n"
894
 
                     "tx1: %f\t"
895
 
                     "ty1: %f\n"
896
 
                     "tx2: %f\t"
897
 
                     "ty2: %f\n",
898
 
                     iter_x.index, iter_y.index,
899
 
                     slice_qx1, slice_qy1,
900
 
                     slice_qx2, slice_qy2,
901
 
                     slice_tx1, slice_ty1,
902
 
                     slice_tx2, slice_ty2);
903
 
 
904
 
          /* Pick and bind opengl texture object */
905
 
          gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
906
 
                                     iter_y.index * iter_x.array->len +
907
 
                                     iter_x.index);
908
 
 
909
 
          tex_coords[0] = slice_tx1;
910
 
          tex_coords[1] = slice_ty1;
911
 
          tex_coords[2] = slice_tx2;
912
 
          tex_coords[3] = slice_ty2;
913
 
          _cogl_journal_log_quad (slice_qx1,
914
 
                                  slice_qy1,
915
 
                                  slice_qx2,
916
 
                                  slice_qy2,
917
 
                                  material,
918
 
                                  1, /* one layer */
919
 
                                  0, /* don't need to use fallbacks */
920
 
                                  gl_handle, /* replace the layer0 texture */
921
 
                                  tex_coords,
922
 
                                  4);
923
 
        }
924
 
    }
925
 
}
926
 
 
927
 
static gboolean
928
 
_cogl_multitexture_unsliced_quad (float        x_1,
929
 
                                  float        y_1,
930
 
                                  float        x_2,
931
 
                                  float        y_2,
932
 
                                  CoglHandle   material,
933
 
                                  guint32      fallback_layers,
934
 
                                  const float *user_tex_coords,
935
 
                                  gint         user_tex_coords_len)
936
 
{
937
 
  int          n_layers = cogl_material_get_n_layers (material);
938
 
  float       *final_tex_coords = alloca (sizeof (float) * 4 * n_layers);
939
 
  const GList *layers;
940
 
  GList       *tmp;
941
 
  int          i;
942
 
 
943
 
  _COGL_GET_CONTEXT (ctx, FALSE);
944
 
 
945
 
  /*
946
 
   * Validate the texture coordinates for this rectangle.
947
 
   */
948
 
  layers = cogl_material_get_layers (material);
949
 
  for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
950
 
    {
951
 
      CoglHandle         layer = (CoglHandle)tmp->data;
952
 
      CoglHandle         tex_handle;
953
 
      CoglTexture       *tex;
954
 
      const float       *in_tex_coords;
955
 
      float             *out_tex_coords;
956
 
      CoglTexSliceSpan  *x_span;
957
 
      CoglTexSliceSpan  *y_span;
958
 
 
959
 
      tex_handle = cogl_material_layer_get_texture (layer);
960
 
 
961
 
      /* COGL_INVALID_HANDLE textures are handled by
962
 
       * _cogl_material_flush_gl_state */
963
 
      if (tex_handle == COGL_INVALID_HANDLE)
964
 
        continue;
965
 
 
966
 
      tex = _cogl_texture_pointer_from_handle (tex_handle);
967
 
 
968
 
      in_tex_coords = &user_tex_coords[i * 4];
969
 
      out_tex_coords = &final_tex_coords[i * 4];
970
 
 
971
 
 
972
 
      /* If the texture has waste or we are using GL_TEXTURE_RECT we
973
 
       * can't handle texture repeating so we check that the texture
974
 
       * coords lie in the range [0,1].
975
 
       *
976
 
       * NB: We already know that no texture matrix is being used
977
 
       * if the texture has waste since we validated that early on.
978
 
       * TODO: check for a texture matrix in the GL_TEXTURE_RECT
979
 
       * case.
980
 
       */
981
 
      if ((
982
 
#if HAVE_COGL_GL
983
 
           tex->gl_target == GL_TEXTURE_RECTANGLE_ARB ||
984
 
#endif
985
 
           _cogl_texture_span_has_waste (tex, 0, 0))
986
 
          && i < user_tex_coords_len / 4
987
 
          && (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0
988
 
              || in_tex_coords[1] < 0 || in_tex_coords[1] > 1.0
989
 
              || in_tex_coords[2] < 0 || in_tex_coords[2] > 1.0
990
 
              || in_tex_coords[3] < 0 || in_tex_coords[3] > 1.0))
991
 
        {
992
 
          if (i == 0)
993
 
            {
994
 
              if (n_layers > 1)
995
 
                {
996
 
                  static gboolean warning_seen = FALSE;
997
 
                  if (!warning_seen)
998
 
                    g_warning ("Skipping layers 1..n of your material since "
999
 
                               "the first layer has waste and you supplied "
1000
 
                               "texture coordinates outside the range [0,1]. "
1001
 
                               "We don't currently support any "
1002
 
                               "multi-texturing using textures with waste "
1003
 
                               "when repeating is necissary so we are "
1004
 
                               "falling back to sliced textures assuming "
1005
 
                               "layer 0 is the most important one keep");
1006
 
                  warning_seen = TRUE;
1007
 
                }
1008
 
              return FALSE;
1009
 
            }
1010
 
          else
1011
 
            {
1012
 
              static gboolean warning_seen = FALSE;
1013
 
              if (!warning_seen)
1014
 
                g_warning ("Skipping layer %d of your material "
1015
 
                           "consisting of a texture with waste since "
1016
 
                           "you have supplied texture coords outside "
1017
 
                           "the range [0,1] (unsupported when "
1018
 
                           "multi-texturing)", i);
1019
 
              warning_seen = TRUE;
1020
 
 
1021
 
              /* NB: marking for fallback will replace the layer with
1022
 
               * a default transparent texture */
1023
 
              fallback_layers |= (1 << i);
1024
 
            }
1025
 
        }
1026
 
 
1027
 
 
1028
 
      /*
1029
 
       * Setup the texture unit...
1030
 
       */
1031
 
 
1032
 
      /* NB: The user might not have supplied texture coordinates for all
1033
 
       * layers... */
1034
 
      if (i < (user_tex_coords_len / 4))
1035
 
        {
1036
 
          GLenum wrap_mode;
1037
 
 
1038
 
          /* If the texture coords are all in the range [0,1] then we want to
1039
 
             clamp the coords to the edge otherwise it can pull in edge pixels
1040
 
             from the wrong side when scaled */
1041
 
          if (in_tex_coords[0] >= 0 && in_tex_coords[0] <= 1.0
1042
 
              && in_tex_coords[1] >= 0 && in_tex_coords[1] <= 1.0
1043
 
              && in_tex_coords[2] >= 0 && in_tex_coords[2] <= 1.0
1044
 
              && in_tex_coords[3] >= 0 && in_tex_coords[3] <= 1.0)
1045
 
            wrap_mode = GL_CLAMP_TO_EDGE;
1046
 
          else
1047
 
            wrap_mode = GL_REPEAT;
1048
 
 
1049
 
          memcpy (out_tex_coords, in_tex_coords, sizeof (GLfloat) * 4);
1050
 
 
1051
 
          _cogl_texture_set_wrap_mode_parameter (tex, wrap_mode);
1052
 
        }
1053
 
      else
1054
 
        {
1055
 
          out_tex_coords[0] = 0; /* tx_1 */
1056
 
          out_tex_coords[1] = 0; /* ty_1 */
1057
 
          out_tex_coords[2] = 1.0; /* tx_2 */
1058
 
          out_tex_coords[3] = 1.0; /* ty_2 */
1059
 
 
1060
 
          _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
1061
 
        }
1062
 
 
1063
 
      /* Don't include the waste in the texture coordinates */
1064
 
      x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
1065
 
      y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
1066
 
 
1067
 
      out_tex_coords[0] =
1068
 
        out_tex_coords[0] * (x_span->size - x_span->waste) / x_span->size;
1069
 
      out_tex_coords[1] =
1070
 
        out_tex_coords[1] * (y_span->size - y_span->waste) / y_span->size;
1071
 
      out_tex_coords[2] =
1072
 
        out_tex_coords[2] * (x_span->size - x_span->waste) / x_span->size;
1073
 
      out_tex_coords[3] =
1074
 
        out_tex_coords[3] * (y_span->size - y_span->waste) / y_span->size;
1075
 
 
1076
 
#if HAVE_COGL_GL
1077
 
      /* Denormalize texture coordinates for rectangle textures */
1078
 
      if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
1079
 
        {
1080
 
          out_tex_coords[0] *= x_span->size;
1081
 
          out_tex_coords[1] *= y_span->size;
1082
 
          out_tex_coords[2] *= x_span->size;
1083
 
          out_tex_coords[3] *= y_span->size;
1084
 
        }
1085
 
#endif
1086
 
    }
1087
 
 
1088
 
  _cogl_journal_log_quad (x_1,
1089
 
                          y_1,
1090
 
                          x_2,
1091
 
                          y_2,
1092
 
                          material,
1093
 
                          n_layers,
1094
 
                          fallback_layers,
1095
 
                          0, /* don't replace the layer0 texture */
1096
 
                          final_tex_coords,
1097
 
                          n_layers * 4);
1098
 
 
1099
 
  return TRUE;
1100
 
}
1101
 
 
1102
 
struct _CoglMutiTexturedRect
1103
 
{
1104
 
  float        x_1;
1105
 
  float        y_1;
1106
 
  float        x_2;
1107
 
  float        y_2;
1108
 
  const float *tex_coords;
1109
 
  gint             tex_coords_len;
1110
 
};
1111
 
 
1112
 
static void
1113
 
_cogl_rectangles_with_multitexture_coords (
1114
 
                                        struct _CoglMutiTexturedRect *rects,
1115
 
                                        gint                          n_rects)
1116
 
{
1117
 
  CoglHandle     material;
1118
 
  const GList   *layers;
1119
 
  int            n_layers;
1120
 
  const GList   *tmp;
1121
 
  guint32        fallback_layers = 0;
1122
 
  gboolean       all_use_sliced_quad_fallback = FALSE;
1123
 
  int            i;
1124
 
 
1125
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1126
 
 
1127
 
  cogl_clip_ensure ();
1128
 
 
1129
 
  material = ctx->source_material;
1130
 
 
1131
 
  layers = cogl_material_get_layers (material);
1132
 
  n_layers = cogl_material_get_n_layers (material);
1133
 
 
1134
 
  /*
1135
 
   * Validate all the layers of the current source material...
1136
 
   */
1137
 
 
1138
 
  for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
1139
 
    {
1140
 
      CoglHandle     layer = tmp->data;
1141
 
      CoglHandle     tex_handle;
1142
 
      CoglTexture   *texture = NULL;
1143
 
      gulong         flags;
1144
 
 
1145
 
      if (cogl_material_layer_get_type (layer)
1146
 
          != COGL_MATERIAL_LAYER_TYPE_TEXTURE)
1147
 
        continue;
1148
 
 
1149
 
      tex_handle = cogl_material_layer_get_texture (layer);
1150
 
 
1151
 
      /* COGL_INVALID_HANDLE textures are handled by
1152
 
       * _cogl_material_flush_gl_state */
1153
 
      if (tex_handle == COGL_INVALID_HANDLE)
1154
 
        continue;
1155
 
 
1156
 
      texture = _cogl_texture_pointer_from_handle (tex_handle);
1157
 
 
1158
 
      /* XXX:
1159
 
       * For now, if the first layer is sliced then all other layers are
1160
 
       * ignored since we currently don't support multi-texturing with
1161
 
       * sliced textures. If the first layer is not sliced then any other
1162
 
       * layers found to be sliced will be skipped. (with a warning)
1163
 
       *
1164
 
       * TODO: Add support for multi-texturing rectangles with sliced
1165
 
       * textures if no texture matrices are in use.
1166
 
       */
1167
 
      if (cogl_texture_is_sliced (tex_handle))
1168
 
        {
1169
 
          if (i == 0)
1170
 
            {
1171
 
              fallback_layers = ~1; /* fallback all except the first layer */
1172
 
              all_use_sliced_quad_fallback = TRUE;
1173
 
              if (tmp->next)
1174
 
                {
1175
 
                  static gboolean warning_seen = FALSE;
1176
 
                  if (!warning_seen)
1177
 
                    g_warning ("Skipping layers 1..n of your material since "
1178
 
                               "the first layer is sliced. We don't currently "
1179
 
                               "support any multi-texturing with sliced "
1180
 
                               "textures but assume layer 0 is the most "
1181
 
                               "important to keep");
1182
 
                  warning_seen = TRUE;
1183
 
                }
1184
 
              break;
1185
 
            }
1186
 
          else
1187
 
            {
1188
 
              static gboolean warning_seen = FALSE;
1189
 
              if (!warning_seen)
1190
 
                g_warning ("Skipping layer %d of your material consisting of "
1191
 
                           "a sliced texture (unsuported for multi texturing)",
1192
 
                           i);
1193
 
              warning_seen = TRUE;
1194
 
 
1195
 
              /* NB: marking for fallback will replace the layer with
1196
 
               * a default transparent texture */
1197
 
              fallback_layers |= (1 << i);
1198
 
              continue;
1199
 
            }
1200
 
        }
1201
 
 
1202
 
      /* We don't support multi texturing using textures with any waste if the
1203
 
       * user has supplied a custom texture matrix, since we don't know if
1204
 
       * the result will end up trying to texture from the waste area. */
1205
 
      flags = _cogl_material_layer_get_flags (layer);
1206
 
      if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX
1207
 
          && _cogl_texture_span_has_waste (texture, 0, 0))
1208
 
        {
1209
 
          static gboolean warning_seen = FALSE;
1210
 
          if (!warning_seen)
1211
 
            g_warning ("Skipping layer %d of your material consisting of a "
1212
 
                       "texture with waste since you have supplied a custom "
1213
 
                       "texture matrix and the result may try to sample from "
1214
 
                       "the waste area of your texture.", i);
1215
 
          warning_seen = TRUE;
1216
 
 
1217
 
          /* NB: marking for fallback will replace the layer with
1218
 
           * a default transparent texture */
1219
 
          fallback_layers |= (1 << i);
1220
 
          continue;
1221
 
        }
1222
 
    }
1223
 
 
1224
 
  /*
1225
 
   * Emit geometry for each of the rectangles...
1226
 
   */
1227
 
 
1228
 
  for (i = 0; i < n_rects; i++)
1229
 
    {
1230
 
      if (all_use_sliced_quad_fallback
1231
 
          || !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1,
1232
 
                                                rects[i].x_2, rects[i].y_2,
1233
 
                                                material,
1234
 
                                                fallback_layers,
1235
 
                                                rects[i].tex_coords,
1236
 
                                                rects[i].tex_coords_len))
1237
 
        {
1238
 
          CoglHandle   first_layer, tex_handle;
1239
 
          CoglTexture *texture;
1240
 
 
1241
 
          first_layer = layers->data;
1242
 
          tex_handle = cogl_material_layer_get_texture (first_layer);
1243
 
          texture = _cogl_texture_pointer_from_handle (tex_handle);
1244
 
          if (rects[i].tex_coords)
1245
 
            _cogl_texture_sliced_quad (texture,
1246
 
                                       material,
1247
 
                                       rects[i].x_1, rects[i].y_1,
1248
 
                                       rects[i].x_2, rects[i].y_2,
1249
 
                                       rects[i].tex_coords[0],
1250
 
                                       rects[i].tex_coords[1],
1251
 
                                       rects[i].tex_coords[2],
1252
 
                                       rects[i].tex_coords[3]);
1253
 
          else
1254
 
            _cogl_texture_sliced_quad (texture,
1255
 
                                       material,
1256
 
                                       rects[i].x_1, rects[i].y_1,
1257
 
                                       rects[i].x_2, rects[i].y_2,
1258
 
                                       0.0f, 0.0f, 1.0f, 1.0f);
1259
 
        }
1260
 
    }
1261
 
 
1262
 
#if 0
1263
 
  /* XXX: The current journal doesn't handle changes to the model view matrix
1264
 
   * so for now we force a flush at the end of every primitive. */
1265
 
  _cogl_journal_flush ();
1266
 
#endif
1267
 
}
1268
 
 
1269
 
void
1270
 
cogl_rectangles (const float *verts,
1271
 
                 guint        n_rects)
1272
 
{
1273
 
  struct _CoglMutiTexturedRect *rects;
1274
 
  int i;
1275
 
 
1276
 
  rects = g_alloca (n_rects * sizeof (struct _CoglMutiTexturedRect));
1277
 
 
1278
 
  for (i = 0; i < n_rects; i++)
1279
 
    {
1280
 
      rects[i].x_1 = verts[i * 4];
1281
 
      rects[i].y_1 = verts[i * 4 + 1];
1282
 
      rects[i].x_2 = verts[i * 4 + 2];
1283
 
      rects[i].y_2 = verts[i * 4 + 3];
1284
 
      rects[i].tex_coords = NULL;
1285
 
      rects[i].tex_coords_len = 0;
1286
 
    }
1287
 
 
1288
 
  _cogl_rectangles_with_multitexture_coords (rects, n_rects);
1289
 
}
1290
 
 
1291
 
void
1292
 
cogl_rectangles_with_texture_coords (const float *verts,
1293
 
                                     guint        n_rects)
1294
 
{
1295
 
  struct _CoglMutiTexturedRect *rects;
1296
 
  int i;
1297
 
 
1298
 
  rects = g_alloca (n_rects * sizeof (struct _CoglMutiTexturedRect));
1299
 
 
1300
 
  for (i = 0; i < n_rects; i++)
1301
 
    {
1302
 
      rects[i].x_1 = verts[i * 8];
1303
 
      rects[i].y_1 = verts[i * 8 + 1];
1304
 
      rects[i].x_2 = verts[i * 8 + 2];
1305
 
      rects[i].y_2 = verts[i * 8 + 3];
1306
 
      /* FIXME: rect should be defined to have a const float *geom;
1307
 
       * instead, to avoid this copy
1308
 
       * rect[i].geom = &verts[n_rects * 8]; */
1309
 
      rects[i].tex_coords = &verts[i * 8 + 4];
1310
 
      rects[i].tex_coords_len = 4;
1311
 
    }
1312
 
 
1313
 
  _cogl_rectangles_with_multitexture_coords (rects, n_rects);
1314
 
}
1315
 
 
1316
 
void
1317
 
cogl_rectangle_with_texture_coords (float x_1,
1318
 
                                    float y_1,
1319
 
                                    float x_2,
1320
 
                                    float y_2,
1321
 
                                    float tx_1,
1322
 
                                    float ty_1,
1323
 
                                    float tx_2,
1324
 
                                    float ty_2)
1325
 
{
1326
 
  float verts[8];
1327
 
 
1328
 
  verts[0] = x_1;
1329
 
  verts[1] = y_1;
1330
 
  verts[2] = x_2;
1331
 
  verts[3] = y_2;
1332
 
  verts[4] = tx_1;
1333
 
  verts[5] = ty_1;
1334
 
  verts[6] = tx_2;
1335
 
  verts[7] = ty_2;
1336
 
 
1337
 
  cogl_rectangles_with_texture_coords (verts, 1);
1338
 
}
1339
 
 
1340
 
void
1341
 
cogl_rectangle_with_multitexture_coords (float        x_1,
1342
 
                                         float        y_1,
1343
 
                                         float        x_2,
1344
 
                                         float        y_2,
1345
 
                                         const float *user_tex_coords,
1346
 
                                         gint         user_tex_coords_len)
1347
 
{
1348
 
  struct _CoglMutiTexturedRect rect;
1349
 
 
1350
 
  rect.x_1 = x_1;
1351
 
  rect.y_1 = y_1;
1352
 
  rect.x_2 = x_2;
1353
 
  rect.y_2 = y_2;
1354
 
  rect.tex_coords = user_tex_coords;
1355
 
  rect.tex_coords_len = user_tex_coords_len;
1356
 
 
1357
 
  _cogl_rectangles_with_multitexture_coords (&rect, 1);
1358
 
}
1359
 
 
1360
 
void
1361
 
cogl_rectangle (float x_1,
1362
 
                float y_1,
1363
 
                float x_2,
1364
 
                float y_2)
1365
 
{
1366
 
  cogl_rectangle_with_multitexture_coords (x_1, y_1,
1367
 
                                           x_2, y_2,
1368
 
                                           NULL, 0);
1369
 
}
1370
 
 
1371
 
static void
1372
 
_cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
1373
 
                              guint              n_vertices,
1374
 
                              guint              stride,
1375
 
                              gboolean           use_color)
1376
 
{
1377
 
  const GList         *layers;
1378
 
  CoglHandle           layer0;
1379
 
  CoglHandle           tex_handle;
1380
 
  CoglTexture         *tex;
1381
 
  CoglTexSliceSpan    *y_span, *x_span;
1382
 
  int                  x, y, tex_num, i;
1383
 
  GLuint               gl_handle;
1384
 
  GLfloat             *v;
1385
 
  CoglMaterialFlushOptions options;
1386
 
 
1387
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1388
 
 
1389
 
  /* We can assume in this case that we have at least one layer in the
1390
 
   * material that corresponds to a sliced cogl texture */
1391
 
  layers = cogl_material_get_layers (ctx->source_material);
1392
 
  layer0 = (CoglHandle)layers->data;
1393
 
  tex_handle = cogl_material_layer_get_texture (layer0);
1394
 
  tex = _cogl_texture_pointer_from_handle (tex_handle);
1395
 
 
1396
 
  v = (GLfloat *)ctx->logged_vertices->data;
1397
 
  for (i = 0; i < n_vertices; i++)
1398
 
    {
1399
 
      guint8 *c;
1400
 
 
1401
 
      v[0] = vertices[i].x;
1402
 
      v[1] = vertices[i].y;
1403
 
      v[2] = vertices[i].z;
1404
 
 
1405
 
      if (use_color)
1406
 
        {
1407
 
          /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */
1408
 
          c = (guint8 *) (v + 5);
1409
 
          c[0] = cogl_color_get_red_byte (&vertices[i].color);
1410
 
          c[1] = cogl_color_get_green_byte (&vertices[i].color);
1411
 
          c[2] = cogl_color_get_blue_byte (&vertices[i].color);
1412
 
          c[3] = cogl_color_get_alpha_byte (&vertices[i].color);
1413
 
        }
1414
 
 
1415
 
      v += stride;
1416
 
    }
1417
 
 
1418
 
  /* Render all of the slices with the full geometry but use a
1419
 
     transparent border color so that any part of the texture not
1420
 
     covered by the slice will be ignored */
1421
 
  tex_num = 0;
1422
 
  for (y = 0; y < tex->slice_y_spans->len; y++)
1423
 
    {
1424
 
      y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
1425
 
 
1426
 
      for (x = 0; x < tex->slice_x_spans->len; x++)
1427
 
        {
1428
 
          x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
1429
 
 
1430
 
          gl_handle = g_array_index (tex->slice_gl_handles, GLuint, tex_num++);
1431
 
 
1432
 
          /* Convert the vertices into an array of GLfloats ready to pass to
1433
 
             OpenGL */
1434
 
          v = (GLfloat *)ctx->logged_vertices->data;
1435
 
          for (i = 0; i < n_vertices; i++)
1436
 
            {
1437
 
              GLfloat *t;
1438
 
              float    tx, ty;
1439
 
 
1440
 
              tx = ((vertices[i].tx
1441
 
                     - ((float)(x_span->start)
1442
 
                        / tex->bitmap.width))
1443
 
                    * tex->bitmap.width / x_span->size);
1444
 
              ty = ((vertices[i].ty
1445
 
                     - ((float)(y_span->start)
1446
 
                        / tex->bitmap.height))
1447
 
                    * tex->bitmap.height / y_span->size);
1448
 
 
1449
 
#if HAVE_COGL_GL
1450
 
              /* Scale the coordinates up for rectangle textures */
1451
 
              if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
1452
 
                {
1453
 
                  tx *= x_span->size;
1454
 
                  ty *= y_span->size;
1455
 
                }
1456
 
#endif
1457
 
 
1458
 
              /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */
1459
 
              t = v + 3;
1460
 
              t[0] = tx;
1461
 
              t[1] = ty;
1462
 
 
1463
 
              v += stride;
1464
 
            }
1465
 
 
1466
 
          options.flags =
1467
 
            COGL_MATERIAL_FLUSH_DISABLE_MASK |
1468
 
            COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
1469
 
          /* disable all except the first layer */
1470
 
          options.disable_layers = (guint32)~1;
1471
 
          options.layer0_override_texture = gl_handle;
1472
 
 
1473
 
          _cogl_material_flush_gl_state (ctx->source_material, &options);
1474
 
          _cogl_flush_matrix_stacks ();
1475
 
 
1476
 
          GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
1477
 
        }
1478
 
    }
1479
 
}
1480
 
 
1481
 
static void
1482
 
_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
1483
 
                                     guint              n_vertices,
1484
 
                                     guint              n_layers,
1485
 
                                     guint              stride,
1486
 
                                     gboolean           use_color,
1487
 
                                     guint32            fallback_layers)
1488
 
{
1489
 
  CoglHandle           material;
1490
 
  const GList         *layers;
1491
 
  int                  i;
1492
 
  GList               *tmp;
1493
 
  CoglTexSliceSpan    *y_span, *x_span;
1494
 
  GLfloat             *v;
1495
 
  CoglMaterialFlushOptions options;
1496
 
 
1497
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1498
 
 
1499
 
 
1500
 
  material = ctx->source_material;
1501
 
  layers = cogl_material_get_layers (material);
1502
 
 
1503
 
  /* Convert the vertices into an array of GLfloats ready to pass to
1504
 
     OpenGL */
1505
 
  for (v = (GLfloat *)ctx->logged_vertices->data, i = 0;
1506
 
       i < n_vertices;
1507
 
       v += stride, i++)
1508
 
    {
1509
 
      guint8 *c;
1510
 
      int     j;
1511
 
 
1512
 
      /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1513
 
      v[0] = vertices[i].x;
1514
 
      v[1] = vertices[i].y;
1515
 
      v[2] = vertices[i].z;
1516
 
 
1517
 
      for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++)
1518
 
        {
1519
 
          CoglHandle   layer = (CoglHandle)tmp->data;
1520
 
          CoglHandle   tex_handle;
1521
 
          CoglTexture *tex;
1522
 
          GLfloat     *t;
1523
 
          float        tx, ty;
1524
 
 
1525
 
          tex_handle = cogl_material_layer_get_texture (layer);
1526
 
 
1527
 
          /* COGL_INVALID_HANDLE textures will be handled in
1528
 
           * _cogl_material_flush_layers_gl_state but there is no need to worry
1529
 
           * about scaling texture coordinates in this case */
1530
 
          if (tex_handle == COGL_INVALID_HANDLE)
1531
 
            continue;
1532
 
 
1533
 
          tex = _cogl_texture_pointer_from_handle (tex_handle);
1534
 
 
1535
 
          y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
1536
 
          x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
1537
 
 
1538
 
          tx = ((vertices[i].tx
1539
 
                 - ((float)(x_span->start)
1540
 
                    / tex->bitmap.width))
1541
 
                * tex->bitmap.width / x_span->size);
1542
 
          ty = ((vertices[i].ty
1543
 
                 - ((float)(y_span->start)
1544
 
                    / tex->bitmap.height))
1545
 
                * tex->bitmap.height / y_span->size);
1546
 
 
1547
 
#if HAVE_COGL_GL
1548
 
          /* Scale the coordinates up for rectangle textures */
1549
 
          if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
1550
 
            {
1551
 
              tx *= x_span->size;
1552
 
              ty *= y_span->size;
1553
 
            }
1554
 
#endif
1555
 
 
1556
 
          /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1557
 
          t = v + 3 + 2 * j;
1558
 
          t[0] = tx;
1559
 
          t[1] = ty;
1560
 
        }
1561
 
 
1562
 
      if (use_color)
1563
 
        {
1564
 
          /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1565
 
          c = (guint8 *) (v + 3 + 2 * n_layers);
1566
 
          c[0] = cogl_color_get_red_byte (&vertices[i].color);
1567
 
          c[1] = cogl_color_get_green_byte (&vertices[i].color);
1568
 
          c[2] = cogl_color_get_blue_byte (&vertices[i].color);
1569
 
          c[3] = cogl_color_get_alpha_byte (&vertices[i].color);
1570
 
        }
1571
 
    }
1572
 
 
1573
 
  options.flags = COGL_MATERIAL_FLUSH_FALLBACK_MASK;
1574
 
  if (use_color)
1575
 
    options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
1576
 
  options.fallback_layers = fallback_layers;
1577
 
  _cogl_material_flush_gl_state (ctx->source_material, &options);
1578
 
  _cogl_flush_matrix_stacks ();
1579
 
 
1580
 
  GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
1581
 
}
1582
 
 
1583
 
void
1584
 
cogl_polygon (CoglTextureVertex *vertices,
1585
 
              guint              n_vertices,
1586
 
              gboolean           use_color)
1587
 
{
1588
 
  CoglHandle           material;
1589
 
  const GList         *layers;
1590
 
  int                  n_layers;
1591
 
  GList               *tmp;
1592
 
  gboolean             use_sliced_polygon_fallback = FALSE;
1593
 
  guint32              fallback_layers = 0;
1594
 
  int                  i;
1595
 
  gulong               enable_flags;
1596
 
  guint                stride;
1597
 
  gsize                stride_bytes;
1598
 
  GLfloat             *v;
1599
 
  int                  prev_n_texcoord_arrays_enabled;
1600
 
 
1601
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1602
 
 
1603
 
  _cogl_journal_flush ();
1604
 
  cogl_clip_ensure ();
1605
 
 
1606
 
  material = ctx->source_material;
1607
 
  layers = cogl_material_get_layers (ctx->source_material);
1608
 
  n_layers = g_list_length ((GList *)layers);
1609
 
 
1610
 
  for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
1611
 
    {
1612
 
      CoglHandle   layer = (CoglHandle)tmp->data;
1613
 
      CoglHandle   tex_handle = cogl_material_layer_get_texture (layer);
1614
 
 
1615
 
      /* COGL_INVALID_HANDLE textures will be handled in
1616
 
       * _cogl_material_flush_layers_gl_state */
1617
 
      if (tex_handle == COGL_INVALID_HANDLE)
1618
 
        continue;
1619
 
 
1620
 
      if (i == 0 && cogl_texture_is_sliced (tex_handle))
1621
 
        {
1622
 
#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2)
1623
 
          {
1624
 
            static gboolean warning_seen = FALSE;
1625
 
            if (!warning_seen)
1626
 
              g_warning ("cogl_polygon does not work for sliced textures "
1627
 
                         "on GL ES");
1628
 
            warning_seen = TRUE;
1629
 
            return;
1630
 
          }
1631
 
#endif
1632
 
          if (n_layers > 1)
1633
 
            {
1634
 
              static gboolean warning_seen = FALSE;
1635
 
              if (!warning_seen)
1636
 
                {
1637
 
                  g_warning ("Disabling layers 1..n since multi-texturing with "
1638
 
                             "cogl_polygon isn't supported when using sliced "
1639
 
                             "textures\n");
1640
 
                  warning_seen = TRUE;
1641
 
                }
1642
 
            }
1643
 
          use_sliced_polygon_fallback = TRUE;
1644
 
          n_layers = 1;
1645
 
 
1646
 
          if (cogl_material_layer_get_min_filter (layer) != GL_NEAREST
1647
 
              || cogl_material_layer_get_mag_filter (layer) != GL_NEAREST)
1648
 
            {
1649
 
              static gboolean warning_seen = FALSE;
1650
 
              if (!warning_seen)
1651
 
                {
1652
 
                  g_warning ("cogl_texture_polygon does not work for sliced textures "
1653
 
                             "when the minification and magnification filters are not "
1654
 
                             "CGL_NEAREST");
1655
 
                  warning_seen = TRUE;
1656
 
                }
1657
 
              return;
1658
 
            }
1659
 
 
1660
 
#ifdef HAVE_COGL_GL
1661
 
          {
1662
 
            CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle);
1663
 
            /* Temporarily change the wrapping mode on all of the slices to use
1664
 
             * a transparent border
1665
 
             * XXX: it's doesn't look like we save/restore this, like
1666
 
             * the comment implies? */
1667
 
            _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER);
1668
 
          }
1669
 
#endif
1670
 
          break;
1671
 
        }
1672
 
 
1673
 
      if (cogl_texture_is_sliced (tex_handle))
1674
 
        {
1675
 
          static gboolean warning_seen = FALSE;
1676
 
          if (!warning_seen)
1677
 
            g_warning ("Disabling layer %d of the current source material, "
1678
 
                       "because texturing with the vertex buffer API is not "
1679
 
                       "currently supported using sliced textures, or "
1680
 
                       "textures with waste\n", i);
1681
 
          warning_seen = TRUE;
1682
 
 
1683
 
          fallback_layers |= (1 << i);
1684
 
          continue;
1685
 
        }
1686
 
    }
1687
 
 
1688
 
  /* Our data is arranged like:
1689
 
   * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */
1690
 
  stride = 3 + (2 * n_layers) + (use_color ? 1 : 0);
1691
 
  stride_bytes = stride * sizeof (GLfloat);
1692
 
 
1693
 
  /* Make sure there is enough space in the global vertex
1694
 
     array. This is used so we can render the polygon with a single
1695
 
     call to OpenGL but still support any number of vertices */
1696
 
  g_array_set_size (ctx->logged_vertices, n_vertices * stride);
1697
 
  v = (GLfloat *)ctx->logged_vertices->data;
1698
 
 
1699
 
  /* Prepare GL state */
1700
 
  enable_flags = COGL_ENABLE_VERTEX_ARRAY;
1701
 
  enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
1702
 
 
1703
 
  if (ctx->enable_backface_culling)
1704
 
    enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
1705
 
 
1706
 
  if (use_color)
1707
 
    {
1708
 
      enable_flags |= COGL_ENABLE_COLOR_ARRAY;
1709
 
      GE( glColorPointer (4, GL_UNSIGNED_BYTE,
1710
 
                          stride_bytes,
1711
 
                          /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1712
 
                          v + 3 + 2 * n_layers) );
1713
 
    }
1714
 
 
1715
 
  cogl_enable (enable_flags);
1716
 
 
1717
 
  GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v));
1718
 
 
1719
 
  for (i = 0; i < n_layers; i++)
1720
 
    {
1721
 
      GE (glClientActiveTexture (GL_TEXTURE0 + i));
1722
 
      GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
1723
 
      GE (glTexCoordPointer (2, GL_FLOAT,
1724
 
                             stride_bytes,
1725
 
                             /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
1726
 
                             v + 3 + 2 * i));
1727
 
    }
1728
 
  prev_n_texcoord_arrays_enabled =
1729
 
    ctx->n_texcoord_arrays_enabled;
1730
 
  ctx->n_texcoord_arrays_enabled = n_layers;
1731
 
  for (; i < prev_n_texcoord_arrays_enabled; i++)
1732
 
    {
1733
 
      GE (glClientActiveTexture (GL_TEXTURE0 + i));
1734
 
      GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
1735
 
    }
1736
 
 
1737
 
  if (use_sliced_polygon_fallback)
1738
 
    _cogl_texture_sliced_polygon (vertices,
1739
 
                                  n_vertices,
1740
 
                                  stride,
1741
 
                                  use_color);
1742
 
  else
1743
 
    _cogl_multitexture_unsliced_polygon (vertices,
1744
 
                                         n_vertices,
1745
 
                                         n_layers,
1746
 
                                         stride,
1747
 
                                         use_color,
1748
 
                                         fallback_layers);
1749
 
 
1750
 
  /* Reset the size of the logged vertex array because rendering
1751
 
     rectangles expects it to start at 0 */
1752
 
  g_array_set_size (ctx->logged_vertices, 0);
1753
 
}
1754
 
 
1755
 
void
1756
 
cogl_path_fill (void)
1757
 
{
1758
 
  cogl_path_fill_preserve ();
1759
 
 
1760
 
  cogl_path_new ();
1761
 
}
1762
 
 
1763
 
void
1764
 
cogl_path_fill_preserve (void)
1765
 
{
1766
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1767
 
 
1768
 
  _cogl_journal_flush ();
1769
 
  cogl_clip_ensure ();
1770
 
 
1771
 
  if (ctx->path_nodes->len == 0)
1772
 
    return;
1773
 
 
1774
 
  _cogl_path_fill_nodes ();
1775
 
}
1776
 
 
1777
 
void
1778
 
cogl_path_stroke (void)
1779
 
{
1780
 
  cogl_path_stroke_preserve ();
1781
 
 
1782
 
  cogl_path_new ();
1783
 
}
1784
 
 
1785
 
void
1786
 
cogl_path_stroke_preserve (void)
1787
 
{
1788
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1789
 
 
1790
 
  if (ctx->path_nodes->len == 0)
1791
 
    return;
1792
 
 
1793
 
  _cogl_journal_flush ();
1794
 
  cogl_clip_ensure ();
1795
 
 
1796
 
  _cogl_path_stroke_nodes();
1797
 
}
1798
 
 
1799
 
void
1800
 
cogl_path_move_to (float x,
1801
 
                   float y)
1802
 
{
1803
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1804
 
 
1805
 
  /* FIXME: handle multiple contours maybe? */
1806
 
 
1807
 
  _cogl_path_add_node (TRUE, x, y);
1808
 
 
1809
 
  ctx->path_start.x = x;
1810
 
  ctx->path_start.y = y;
1811
 
 
1812
 
  ctx->path_pen = ctx->path_start;
1813
 
}
1814
 
 
1815
 
void
1816
 
cogl_path_rel_move_to (float x,
1817
 
                       float y)
1818
 
{
1819
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1820
 
 
1821
 
  cogl_path_move_to (ctx->path_pen.x + x,
1822
 
                     ctx->path_pen.y + y);
1823
 
}
1824
 
 
1825
 
void
1826
 
cogl_path_line_to (float x,
1827
 
                   float y)
1828
 
{
1829
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1830
 
 
1831
 
  _cogl_path_add_node (FALSE, x, y);
1832
 
 
1833
 
  ctx->path_pen.x = x;
1834
 
  ctx->path_pen.y = y;
1835
 
}
1836
 
 
1837
 
void
1838
 
cogl_path_rel_line_to (float x,
1839
 
                       float y)
1840
 
{
1841
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1842
 
 
1843
 
  cogl_path_line_to (ctx->path_pen.x + x,
1844
 
                     ctx->path_pen.y + y);
1845
 
}
1846
 
 
1847
 
void
1848
 
cogl_path_close (void)
1849
 
{
1850
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1851
 
 
1852
 
  _cogl_path_add_node (FALSE, ctx->path_start.x, ctx->path_start.y);
1853
 
  ctx->path_pen = ctx->path_start;
1854
 
}
1855
 
 
1856
 
void
1857
 
cogl_path_new (void)
1858
 
{
1859
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1860
 
 
1861
 
  g_array_set_size (ctx->path_nodes, 0);
1862
 
}
1863
 
 
1864
 
void
1865
 
cogl_path_line (float x_1,
1866
 
                float y_1,
1867
 
                float x_2,
1868
 
                float y_2)
1869
 
{
1870
 
  cogl_path_move_to (x_1, y_1);
1871
 
  cogl_path_line_to (x_2, y_2);
1872
 
}
1873
 
 
1874
 
void
1875
 
cogl_path_polyline (float *coords,
1876
 
                    gint num_points)
1877
 
{
1878
 
  gint c = 0;
1879
 
 
1880
 
  cogl_path_move_to (coords[0], coords[1]);
1881
 
 
1882
 
  for (c = 1; c < num_points; ++c)
1883
 
    cogl_path_line_to (coords[2*c], coords[2*c+1]);
1884
 
}
1885
 
 
1886
 
void
1887
 
cogl_path_polygon (float *coords,
1888
 
                   gint          num_points)
1889
 
{
1890
 
  cogl_path_polyline (coords, num_points);
1891
 
  cogl_path_close ();
1892
 
}
1893
 
 
1894
 
void
1895
 
cogl_path_rectangle (float x_1,
1896
 
                     float y_1,
1897
 
                     float x_2,
1898
 
                     float y_2)
1899
 
{
1900
 
  cogl_path_move_to (x_1, y_1);
1901
 
  cogl_path_line_to (x_2, y_1);
1902
 
  cogl_path_line_to (x_2, y_2);
1903
 
  cogl_path_line_to (x_1, y_2);
1904
 
  cogl_path_close   ();
1905
 
}
1906
 
 
1907
 
static void
1908
 
_cogl_path_arc (float center_x,
1909
 
                float center_y,
1910
 
                float radius_x,
1911
 
                float radius_y,
1912
 
                float angle_1,
1913
 
                float angle_2,
1914
 
                float angle_step,
1915
 
                guint        move_first)
1916
 
{
1917
 
  float a     = 0x0;
1918
 
  float cosa  = 0x0;
1919
 
  float sina  = 0x0;
1920
 
  float px    = 0x0;
1921
 
  float py    = 0x0;
1922
 
 
1923
 
  /* Fix invalid angles */
1924
 
 
1925
 
  if (angle_1 == angle_2 || angle_step == 0x0)
1926
 
    return;
1927
 
 
1928
 
  if (angle_step < 0x0)
1929
 
    angle_step = -angle_step;
1930
 
 
1931
 
  /* Walk the arc by given step */
1932
 
 
1933
 
  a = angle_1;
1934
 
  while (a != angle_2)
1935
 
    {
1936
 
      cosa = cosf (a * (G_PI/180.0));
1937
 
      sina = sinf (a * (G_PI/180.0));
1938
 
 
1939
 
      px = center_x + (cosa * radius_x);
1940
 
      py = center_y + (sina * radius_y);
1941
 
 
1942
 
      if (a == angle_1 && move_first)
1943
 
        cogl_path_move_to (px, py);
1944
 
      else
1945
 
        cogl_path_line_to (px, py);
1946
 
 
1947
 
      if (G_LIKELY (angle_2 > angle_1))
1948
 
        {
1949
 
          a += angle_step;
1950
 
          if (a > angle_2)
1951
 
            a = angle_2;
1952
 
        }
1953
 
      else
1954
 
        {
1955
 
          a -= angle_step;
1956
 
          if (a < angle_2)
1957
 
            a = angle_2;
1958
 
        }
1959
 
    }
1960
 
 
1961
 
  /* Make sure the final point is drawn */
1962
 
 
1963
 
  cosa = cosf (angle_2 * (G_PI/180.0));
1964
 
  sina = sinf (angle_2 * (G_PI/180.0));
1965
 
 
1966
 
  px = center_x + (cosa * radius_x);
1967
 
  py = center_y + (sina * radius_y);
1968
 
 
1969
 
  cogl_path_line_to (px, py);
1970
 
}
1971
 
 
1972
 
void
1973
 
cogl_path_arc (float center_x,
1974
 
               float center_y,
1975
 
               float radius_x,
1976
 
               float radius_y,
1977
 
               float angle_1,
1978
 
               float angle_2)
1979
 
{
1980
 
  float angle_step = 10;
1981
 
  /* it is documented that a move to is needed to create a freestanding
1982
 
   * arc
1983
 
   */
1984
 
  _cogl_path_arc (center_x,   center_y,
1985
 
                  radius_x,   radius_y,
1986
 
                  angle_1,    angle_2,
1987
 
                  angle_step, 0 /* no move */);
1988
 
}
1989
 
 
1990
 
 
1991
 
void
1992
 
cogl_path_arc_rel (float center_x,
1993
 
                   float center_y,
1994
 
                   float radius_x,
1995
 
                   float radius_y,
1996
 
                   float angle_1,
1997
 
                   float angle_2,
1998
 
                   float angle_step)
1999
 
{
2000
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
2001
 
 
2002
 
  _cogl_path_arc (ctx->path_pen.x + center_x,
2003
 
                  ctx->path_pen.y + center_y,
2004
 
                  radius_x,   radius_y,
2005
 
                  angle_1,    angle_2,
2006
 
                  angle_step, 0 /* no move */);
2007
 
}
2008
 
 
2009
 
void
2010
 
cogl_path_ellipse (float center_x,
2011
 
                   float center_y,
2012
 
                   float radius_x,
2013
 
                   float radius_y)
2014
 
{
2015
 
  float angle_step = 10;
2016
 
 
2017
 
  /* FIXME: if shows to be slow might be optimized
2018
 
   * by mirroring just a quarter of it */
2019
 
 
2020
 
  _cogl_path_arc (center_x, center_y,
2021
 
                  radius_x, radius_y,
2022
 
                  0, 360,
2023
 
                  angle_step, 1 /* move first */);
2024
 
 
2025
 
  cogl_path_close();
2026
 
}
2027
 
 
2028
 
void
2029
 
cogl_path_round_rectangle (float x_1,
2030
 
                           float y_1,
2031
 
                           float x_2,
2032
 
                           float y_2,
2033
 
                           float radius,
2034
 
                           float arc_step)
2035
 
{
2036
 
  float inner_width = x_2 - x_1 - radius * 2;
2037
 
  float inner_height = y_2 - y_1 - radius * 2;
2038
 
 
2039
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
2040
 
 
2041
 
  cogl_path_move_to (x_1, y_1 + radius);
2042
 
  cogl_path_arc_rel (radius, 0,
2043
 
                     radius, radius,
2044
 
                     180,
2045
 
                     270,
2046
 
                     arc_step);
2047
 
 
2048
 
  cogl_path_line_to       (ctx->path_pen.x + inner_width,
2049
 
                           ctx->path_pen.y);
2050
 
  cogl_path_arc_rel       (0, radius,
2051
 
                           radius, radius,
2052
 
                           -90,
2053
 
                           0,
2054
 
                           arc_step);
2055
 
 
2056
 
  cogl_path_line_to       (ctx->path_pen.x,
2057
 
                           ctx->path_pen.y + inner_height);
2058
 
 
2059
 
  cogl_path_arc_rel       (-radius, 0,
2060
 
                           radius, radius,
2061
 
                           0,
2062
 
                           90,
2063
 
                           arc_step);
2064
 
 
2065
 
  cogl_path_line_to       (ctx->path_pen.x - inner_width,
2066
 
                           ctx->path_pen.y);
2067
 
  cogl_path_arc_rel       (0, -radius,
2068
 
                           radius, radius,
2069
 
                           90,
2070
 
                           180,
2071
 
                           arc_step);
2072
 
 
2073
 
  cogl_path_close ();
2074
 
}
2075
 
 
2076
 
 
2077
 
static void
2078
 
_cogl_path_bezier3_sub (CoglBezCubic *cubic)
2079
 
{
2080
 
  CoglBezCubic   cubics[_COGL_MAX_BEZ_RECURSE_DEPTH];
2081
 
  CoglBezCubic  *cleft;
2082
 
  CoglBezCubic  *cright;
2083
 
  CoglBezCubic  *c;
2084
 
  floatVec2  dif1;
2085
 
  floatVec2  dif2;
2086
 
  floatVec2  mm;
2087
 
  floatVec2  c1;
2088
 
  floatVec2  c2;
2089
 
  floatVec2  c3;
2090
 
  floatVec2  c4;
2091
 
  floatVec2  c5;
2092
 
  gint           cindex;
2093
 
 
2094
 
  /* Put first curve on stack */
2095
 
  cubics[0] = *cubic;
2096
 
  cindex    =  0;
2097
 
 
2098
 
  while (cindex >= 0)
2099
 
    {
2100
 
      c = &cubics[cindex];
2101
 
 
2102
 
 
2103
 
      /* Calculate distance of control points from their
2104
 
       * counterparts on the line between end points */
2105
 
      dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x;
2106
 
      dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y;
2107
 
      dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x;
2108
 
      dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y;
2109
 
 
2110
 
      if (dif1.x < 0)
2111
 
        dif1.x = -dif1.x;
2112
 
      if (dif1.y < 0)
2113
 
        dif1.y = -dif1.y;
2114
 
      if (dif2.x < 0)
2115
 
        dif2.x = -dif2.x;
2116
 
      if (dif2.y < 0)
2117
 
        dif2.y = -dif2.y;
2118
 
 
2119
 
 
2120
 
      /* Pick the greatest of two distances */
2121
 
      if (dif1.x < dif2.x) dif1.x = dif2.x;
2122
 
      if (dif1.y < dif2.y) dif1.y = dif2.y;
2123
 
 
2124
 
      /* Cancel if the curve is flat enough */
2125
 
      if (dif1.x + dif1.y <= 1.0 ||
2126
 
          cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1)
2127
 
        {
2128
 
          /* Add subdivision point (skip last) */
2129
 
          if (cindex == 0)
2130
 
            return;
2131
 
 
2132
 
          _cogl_path_add_node (FALSE, c->p4.x, c->p4.y);
2133
 
 
2134
 
          --cindex;
2135
 
 
2136
 
          continue;
2137
 
        }
2138
 
 
2139
 
      /* Left recursion goes on top of stack! */
2140
 
      cright = c; cleft = &cubics[++cindex];
2141
 
 
2142
 
      /* Subdivide into 2 sub-curves */
2143
 
      c1.x = ((c->p1.x + c->p2.x) / 2);
2144
 
      c1.y = ((c->p1.y + c->p2.y) / 2);
2145
 
      mm.x = ((c->p2.x + c->p3.x) / 2);
2146
 
      mm.y = ((c->p2.y + c->p3.y) / 2);
2147
 
      c5.x = ((c->p3.x + c->p4.x) / 2);
2148
 
      c5.y = ((c->p3.y + c->p4.y) / 2);
2149
 
 
2150
 
      c2.x = ((c1.x + mm.x) / 2);
2151
 
      c2.y = ((c1.y + mm.y) / 2);
2152
 
      c4.x = ((mm.x + c5.x) / 2);
2153
 
      c4.y = ((mm.y + c5.y) / 2);
2154
 
 
2155
 
      c3.x = ((c2.x + c4.x) / 2);
2156
 
      c3.y = ((c2.y + c4.y) / 2);
2157
 
 
2158
 
      /* Add left recursion to stack */
2159
 
      cleft->p1 = c->p1;
2160
 
      cleft->p2 = c1;
2161
 
      cleft->p3 = c2;
2162
 
      cleft->p4 = c3;
2163
 
 
2164
 
      /* Add right recursion to stack */
2165
 
      cright->p1 = c3;
2166
 
      cright->p2 = c4;
2167
 
      cright->p3 = c5;
2168
 
      cright->p4 = c->p4;
2169
 
    }
2170
 
}
2171
 
 
2172
 
void
2173
 
cogl_path_curve_to (float x_1,
2174
 
                    float y_1,
2175
 
                    float x_2,
2176
 
                    float y_2,
2177
 
                    float x_3,
2178
 
                    float y_3)
2179
 
{
2180
 
  CoglBezCubic cubic;
2181
 
 
2182
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
2183
 
 
2184
 
  /* Prepare cubic curve */
2185
 
  cubic.p1 = ctx->path_pen;
2186
 
  cubic.p2.x = x_1;
2187
 
  cubic.p2.y = y_1;
2188
 
  cubic.p3.x = x_2;
2189
 
  cubic.p3.y = y_2;
2190
 
  cubic.p4.x = x_3;
2191
 
  cubic.p4.y = y_3;
2192
 
 
2193
 
  /* Run subdivision */
2194
 
  _cogl_path_bezier3_sub (&cubic);
2195
 
 
2196
 
  /* Add last point */
2197
 
  _cogl_path_add_node (FALSE, cubic.p4.x, cubic.p4.y);
2198
 
  ctx->path_pen = cubic.p4;
2199
 
}
2200
 
 
2201
 
void
2202
 
cogl_path_rel_curve_to (float x_1,
2203
 
                        float y_1,
2204
 
                        float x_2,
2205
 
                        float y_2,
2206
 
                        float x_3,
2207
 
                        float y_3)
2208
 
{
2209
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
2210
 
 
2211
 
  cogl_path_curve_to (ctx->path_pen.x + x_1,
2212
 
                      ctx->path_pen.y + y_1,
2213
 
                      ctx->path_pen.x + x_2,
2214
 
                      ctx->path_pen.y + y_2,
2215
 
                      ctx->path_pen.x + x_3,
2216
 
                      ctx->path_pen.y + y_3);
2217
 
}
2218
 
 
2219
 
 
2220
 
/* If second order beziers were needed the following code could
2221
 
 * be re-enabled:
2222
 
 */
2223
 
#if 0
2224
 
 
2225
 
static void
2226
 
_cogl_path_bezier2_sub (CoglBezQuad *quad)
2227
 
{
2228
 
  CoglBezQuad     quads[_COGL_MAX_BEZ_RECURSE_DEPTH];
2229
 
  CoglBezQuad    *qleft;
2230
 
  CoglBezQuad    *qright;
2231
 
  CoglBezQuad    *q;
2232
 
  floatVec2   mid;
2233
 
  floatVec2   dif;
2234
 
  floatVec2   c1;
2235
 
  floatVec2   c2;
2236
 
  floatVec2   c3;
2237
 
  gint            qindex;
2238
 
 
2239
 
  /* Put first curve on stack */
2240
 
  quads[0] = *quad;
2241
 
  qindex   =  0;
2242
 
 
2243
 
  /* While stack is not empty */
2244
 
  while (qindex >= 0)
2245
 
    {
2246
 
 
2247
 
      q = &quads[qindex];
2248
 
 
2249
 
      /* Calculate distance of control point from its
2250
 
       * counterpart on the line between end points */
2251
 
      mid.x = ((q->p1.x + q->p3.x) / 2);
2252
 
      mid.y = ((q->p1.y + q->p3.y) / 2);
2253
 
      dif.x = (q->p2.x - mid.x);
2254
 
      dif.y = (q->p2.y - mid.y);
2255
 
      if (dif.x < 0) dif.x = -dif.x;
2256
 
      if (dif.y < 0) dif.y = -dif.y;
2257
 
 
2258
 
      /* Cancel if the curve is flat enough */
2259
 
      if (dif.x + dif.y <= 1.0 ||
2260
 
          qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1)
2261
 
        {
2262
 
          /* Add subdivision point (skip last) */
2263
 
          if (qindex == 0) return;
2264
 
          _cogl_path_add_node (FALSE, q->p3.x, q->p3.y);
2265
 
          --qindex; continue;
2266
 
        }
2267
 
 
2268
 
      /* Left recursion goes on top of stack! */
2269
 
      qright = q; qleft = &quads[++qindex];
2270
 
 
2271
 
      /* Subdivide into 2 sub-curves */
2272
 
      c1.x = ((q->p1.x + q->p2.x) / 2);
2273
 
      c1.y = ((q->p1.y + q->p2.y) / 2);
2274
 
      c3.x = ((q->p2.x + q->p3.x) / 2);
2275
 
      c3.y = ((q->p2.y + q->p3.y) / 2);
2276
 
      c2.x = ((c1.x + c3.x) / 2);
2277
 
      c2.y = ((c1.y + c3.y) / 2);
2278
 
 
2279
 
      /* Add left recursion onto stack */
2280
 
      qleft->p1 = q->p1;
2281
 
      qleft->p2 = c1;
2282
 
      qleft->p3 = c2;
2283
 
 
2284
 
      /* Add right recursion onto stack */
2285
 
      qright->p1 = c2;
2286
 
      qright->p2 = c3;
2287
 
      qright->p3 = q->p3;
2288
 
    }
2289
 
}
2290
 
 
2291
 
void
2292
 
cogl_path_curve2_to (float x_1,
2293
 
                     float y_1,
2294
 
                     float x_2,
2295
 
                     float y_2)
2296
 
{
2297
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
2298
 
 
2299
 
  CoglBezQuad quad;
2300
 
 
2301
 
  /* Prepare quadratic curve */
2302
 
  quad.p1 = ctx->path_pen;
2303
 
  quad.p2.x = x_1;
2304
 
  quad.p2.y = y_1;
2305
 
  quad.p3.x = x_2;
2306
 
  quad.p3.y = y_2;
2307
 
 
2308
 
  /* Run subdivision */
2309
 
  _cogl_path_bezier2_sub (&quad);
2310
 
 
2311
 
  /* Add last point */
2312
 
  _cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
2313
 
  ctx->path_pen = quad.p3;
2314
 
}
2315
 
 
2316
 
void
2317
 
cogl_rel_curve2_to (float x_1,
2318
 
                    float y_1,
2319
 
                    float x_2,
2320
 
                    float y_2)
2321
 
{
2322
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
2323
 
 
2324
 
  cogl_path_curve2_to (ctx->path_pen.x + x_1,
2325
 
                       ctx->path_pen.y + y_1,
2326
 
                       ctx->path_pen.x + x_2,
2327
 
                       ctx->path_pen.y + y_2);
2328
 
}
2329
 
#endif