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

« back to all changes in this revision

Viewing changes to clutter/pango/cogl-pango-display-list.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
 
 * Clutter.
3
 
 *
4
 
 * An OpenGL based 'interactive canvas' library.
5
 
 *
6
 
 * Authored By Neil Roberts  <neil@linux.intel.com>
7
 
 *
8
 
 * Copyright (C) 2009 Intel Corporation.
9
 
 *
10
 
 * This library is free software; you can redistribute it and/or
11
 
 * modify it under the terms of the GNU Lesser General Public
12
 
 * License as published by the Free Software Foundation; either
13
 
 * version 2 of the License, or (at your option) any later version.
14
 
 *
15
 
 * This library is distributed in the hope that it will be useful,
16
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 
 * Lesser General Public License for more details.
19
 
 *
20
 
 * You should have received a copy of the GNU Lesser General Public
21
 
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22
 
 */
23
 
 
24
 
#ifdef HAVE_CONFIG_H
25
 
#include "config.h"
26
 
#endif
27
 
 
28
 
#include <glib.h>
29
 
#include <cogl/cogl.h>
30
 
#include <string.h>
31
 
 
32
 
#include "cogl-pango-display-list.h"
33
 
 
34
 
typedef enum
35
 
{
36
 
  COGL_PANGO_DISPLAY_LIST_TEXTURE,
37
 
  COGL_PANGO_DISPLAY_LIST_RECTANGLE,
38
 
  COGL_PANGO_DISPLAY_LIST_TRAPEZOID
39
 
} CoglPangoDisplayListNodeType;
40
 
 
41
 
typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode;
42
 
typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex;
43
 
 
44
 
struct _CoglPangoDisplayList
45
 
{
46
 
  gboolean   color_override;
47
 
  CoglColor  color;
48
 
  GSList    *nodes;
49
 
  GSList    *last_node;
50
 
};
51
 
 
52
 
struct _CoglPangoDisplayListNode
53
 
{
54
 
  CoglPangoDisplayListNodeType type;
55
 
 
56
 
  gboolean color_override;
57
 
  CoglColor color;
58
 
 
59
 
  union
60
 
  {
61
 
    struct
62
 
    {
63
 
      /* The texture to render these coords from */
64
 
      CoglHandle  texture;
65
 
      /* Array of vertex data to render out of this texture */
66
 
      GArray     *verts;
67
 
      /* A VBO representing those vertices */
68
 
      CoglHandle  vertex_buffer;
69
 
    } texture;
70
 
 
71
 
    struct
72
 
    {
73
 
      float x_1, y_1;
74
 
      float x_2, y_2;
75
 
    } rectangle;
76
 
 
77
 
    struct
78
 
    {
79
 
      float y_1;
80
 
      float x_11;
81
 
      float x_21;
82
 
      float y_2;
83
 
      float x_12;
84
 
      float x_22;
85
 
    } trapezoid;
86
 
  } d;
87
 
};
88
 
 
89
 
struct _CoglPangoDisplayListVertex
90
 
{
91
 
  float x, y, t_x, t_y;
92
 
};
93
 
 
94
 
CoglPangoDisplayList *
95
 
_cogl_pango_display_list_new (void)
96
 
{
97
 
  return g_slice_new0 (CoglPangoDisplayList);
98
 
}
99
 
 
100
 
static void
101
 
_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl,
102
 
                                      CoglPangoDisplayListNode *node)
103
 
{
104
 
  if (dl->last_node)
105
 
    dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node);
106
 
  else
107
 
    dl->last_node = dl->nodes = g_slist_prepend (NULL, node);
108
 
}
109
 
 
110
 
void
111
 
_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl,
112
 
                                             const CoglColor *color)
113
 
{
114
 
  dl->color_override = TRUE;
115
 
  dl->color = *color;
116
 
}
117
 
 
118
 
void
119
 
_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl)
120
 
{
121
 
  dl->color_override = FALSE;
122
 
}
123
 
 
124
 
void
125
 
_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
126
 
                                      CoglHandle texture,
127
 
                                      float x_1, float y_1,
128
 
                                      float x_2, float y_2,
129
 
                                      float tx_1, float ty_1,
130
 
                                      float tx_2, float ty_2)
131
 
{
132
 
  CoglPangoDisplayListNode *node;
133
 
  CoglPangoDisplayListVertex *verts;
134
 
 
135
 
  /* Add to the last node if it is a texture node with the same
136
 
     target texture */
137
 
  if (dl->last_node
138
 
      && (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE
139
 
      && node->d.texture.texture == texture
140
 
      && (dl->color_override
141
 
          ? (node->color_override && cogl_color_equal (&dl->color, &node->color))
142
 
          : !node->color_override))
143
 
    {
144
 
      /* Get rid of the vertex buffer so that it will be recreated */
145
 
      if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
146
 
        {
147
 
          cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
148
 
          node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
149
 
        }
150
 
    }
151
 
  else
152
 
    {
153
 
      /* Otherwise create a new node */
154
 
      node = g_slice_new (CoglPangoDisplayListNode);
155
 
 
156
 
      node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE;
157
 
      node->color_override = dl->color_override;
158
 
      node->color = dl->color;
159
 
      node->d.texture.texture = cogl_texture_ref (texture);
160
 
      node->d.texture.verts
161
 
        = g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListVertex));
162
 
      node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
163
 
 
164
 
      _cogl_pango_display_list_append_node (dl, node);
165
 
    }
166
 
 
167
 
  g_array_set_size (node->d.texture.verts,
168
 
                    node->d.texture.verts->len + 4);
169
 
  verts = &g_array_index (node->d.texture.verts,
170
 
                          CoglPangoDisplayListVertex,
171
 
                          node->d.texture.verts->len - 4);
172
 
 
173
 
  verts->x = x_1;
174
 
  verts->y = y_1;
175
 
  verts->t_x = tx_1;
176
 
  verts->t_y = ty_1;
177
 
  verts++;
178
 
  verts->x = x_1;
179
 
  verts->y = y_2;
180
 
  verts->t_x = tx_1;
181
 
  verts->t_y = ty_2;
182
 
  verts++;
183
 
  verts->x = x_2;
184
 
  verts->y = y_2;
185
 
  verts->t_x = tx_2;
186
 
  verts->t_y = ty_2;
187
 
  verts++;
188
 
  verts->x = x_2;
189
 
  verts->y = y_1;
190
 
  verts->t_x = tx_2;
191
 
  verts->t_y = ty_1;
192
 
}
193
 
 
194
 
void
195
 
_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
196
 
                                        float x_1, float y_1,
197
 
                                        float x_2, float y_2)
198
 
{
199
 
  CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
200
 
 
201
 
  node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE;
202
 
  node->color_override = dl->color_override;
203
 
  node->color = dl->color;
204
 
  node->d.rectangle.x_1 = x_1;
205
 
  node->d.rectangle.y_1 = y_1;
206
 
  node->d.rectangle.x_2 = x_2;
207
 
  node->d.rectangle.y_2 = y_2;
208
 
 
209
 
  _cogl_pango_display_list_append_node (dl, node);
210
 
}
211
 
 
212
 
void
213
 
_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
214
 
                                        float y_1,
215
 
                                        float x_11,
216
 
                                        float x_21,
217
 
                                        float y_2,
218
 
                                        float x_12,
219
 
                                        float x_22)
220
 
{
221
 
  CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
222
 
 
223
 
  node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID;
224
 
  node->color_override = dl->color_override;
225
 
  node->color = dl->color;
226
 
  node->d.trapezoid.y_1 = y_1;
227
 
  node->d.trapezoid.x_11 = x_11;
228
 
  node->d.trapezoid.x_21 = x_21;
229
 
  node->d.trapezoid.y_2 = y_2;
230
 
  node->d.trapezoid.x_12 = x_12;
231
 
  node->d.trapezoid.x_22 = x_22;
232
 
 
233
 
  _cogl_pango_display_list_append_node (dl, node);
234
 
}
235
 
 
236
 
static void
237
 
_cogl_pango_display_list_render_texture (CoglHandle material,
238
 
                                         const CoglColor *color,
239
 
                                         CoglPangoDisplayListNode *node)
240
 
{
241
 
  CoglColor premult_color = *color;
242
 
  cogl_material_set_layer (material, 0, node->d.texture.texture);
243
 
  cogl_material_set_color (material, &premult_color);
244
 
  cogl_set_source (material);
245
 
 
246
 
  /* For small runs of text like icon labels, we can get better performance
247
 
   * going through the Cogl journal since text may then be batched together
248
 
   * with other geometry. */
249
 
  /* FIXME: 100 is a number I plucked out of thin air; it would be good
250
 
   * to determine this empirically! */
251
 
  if (node->d.texture.verts->len < 100)
252
 
    {
253
 
      int i;
254
 
 
255
 
      for (i = 0; i < node->d.texture.verts->len; i += 4)
256
 
        {
257
 
          CoglPangoDisplayListVertex *v0 =
258
 
            &g_array_index (node->d.texture.verts,
259
 
                            CoglPangoDisplayListVertex, i);
260
 
          CoglPangoDisplayListVertex *v1 =
261
 
            &g_array_index (node->d.texture.verts,
262
 
                            CoglPangoDisplayListVertex, i + 2);
263
 
          cogl_rectangle_with_texture_coords (v0->x, v0->y, v1->x, v1->y,
264
 
                                              v0->t_x, v0->t_y,
265
 
                                              v1->t_x, v1->t_y);
266
 
        }
267
 
 
268
 
      return;
269
 
    }
270
 
 
271
 
  /* It's expensive to go through the Cogl journal for large runs
272
 
   * of text in part because the journal transforms the quads in software
273
 
   * to avoid changing the modelview matrix. So for larger runs of text
274
 
   * we load the vertices into a VBO, and this has the added advantage
275
 
   * that if the text doesn't change from frame to frame the VBO can
276
 
   * be re-used avoiding the repeated cost of validating the data and
277
 
   * mapping it into the GPU... */
278
 
 
279
 
  if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE)
280
 
    {
281
 
      CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len);
282
 
 
283
 
      cogl_vertex_buffer_add (vb, "gl_Vertex", 2,
284
 
                              COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
285
 
                              sizeof (CoglPangoDisplayListVertex),
286
 
                              &g_array_index (node->d.texture.verts,
287
 
                                              CoglPangoDisplayListVertex, 0).x);
288
 
      cogl_vertex_buffer_add (vb, "gl_MultiTexCoord0", 2,
289
 
                              COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
290
 
                              sizeof (CoglPangoDisplayListVertex),
291
 
                              &g_array_index (node->d.texture.verts,
292
 
                                              CoglPangoDisplayListVertex,
293
 
                                              0).t_x);
294
 
      cogl_vertex_buffer_submit (vb);
295
 
 
296
 
      node->d.texture.vertex_buffer = vb;
297
 
    }
298
 
 
299
 
 
300
 
#ifdef CLUTTER_COGL_HAS_GL
301
 
 
302
 
  cogl_vertex_buffer_draw (node->d.texture.vertex_buffer,
303
 
                           GL_QUADS,
304
 
                           0, node->d.texture.verts->len);
305
 
 
306
 
#else /* CLUTTER_COGL_HAS_GL */
307
 
  {
308
 
    /* GLES doesn't support GL_QUADS so instead we use a VBO with
309
 
       indexed vertices to generate GL_TRIANGLES from the quads */
310
 
 
311
 
    int n_indices = node->d.texture.verts->len / 4 * 6;
312
 
    CoglHandle indices_vbo
313
 
      = cogl_vertex_buffer_indices_get_for_quads (n_indices);
314
 
 
315
 
    cogl_vertex_buffer_draw_elements (node->d.texture.vertex_buffer,
316
 
                                      COGL_VERTICES_MODE_TRIANGLES,
317
 
                                      indices_vbo,
318
 
                                      0, node->d.texture.verts->len - 1,
319
 
                                      0, n_indices);
320
 
  }
321
 
#endif /* CLUTTER_COGL_HAS_GL */
322
 
}
323
 
 
324
 
void
325
 
_cogl_pango_display_list_render (CoglPangoDisplayList *dl,
326
 
                                 const CoglColor *color,
327
 
                                 CoglHandle glyph_material,
328
 
                                 CoglHandle solid_material)
329
 
{
330
 
  GSList *l;
331
 
 
332
 
  for (l = dl->nodes; l; l = l->next)
333
 
    {
334
 
      CoglPangoDisplayListNode *node = l->data;
335
 
      CoglColor draw_color;
336
 
 
337
 
      if (node->color_override)
338
 
        /* Use the override color but preserve the alpha from the
339
 
           draw color */
340
 
        cogl_color_set_from_4ub (&draw_color,
341
 
                                 cogl_color_get_red_byte (&node->color),
342
 
                                 cogl_color_get_green_byte (&node->color),
343
 
                                 cogl_color_get_blue_byte (&node->color),
344
 
                                 cogl_color_get_alpha_byte (color));
345
 
      else
346
 
        draw_color = *color;
347
 
      cogl_color_premultiply (&draw_color);
348
 
 
349
 
      switch (node->type)
350
 
        {
351
 
        case COGL_PANGO_DISPLAY_LIST_TEXTURE:
352
 
          _cogl_pango_display_list_render_texture (glyph_material,
353
 
                                                   &draw_color, node);
354
 
          break;
355
 
 
356
 
        case COGL_PANGO_DISPLAY_LIST_RECTANGLE:
357
 
          cogl_material_set_color (solid_material, &draw_color);
358
 
          cogl_set_source (solid_material);
359
 
          cogl_rectangle (node->d.rectangle.x_1,
360
 
                          node->d.rectangle.y_1,
361
 
                          node->d.rectangle.x_2,
362
 
                          node->d.rectangle.y_2);
363
 
          break;
364
 
 
365
 
        case COGL_PANGO_DISPLAY_LIST_TRAPEZOID:
366
 
          {
367
 
            float points[8];
368
 
 
369
 
            points[0] =  node->d.trapezoid.x_11;
370
 
            points[1] =  node->d.trapezoid.y_1;
371
 
            points[2] =  node->d.trapezoid.x_12;
372
 
            points[3] =  node->d.trapezoid.y_2;
373
 
            points[4] =  node->d.trapezoid.x_22;
374
 
            points[5] =  node->d.trapezoid.y_2;
375
 
            points[6] =  node->d.trapezoid.x_21;
376
 
            points[7] =  node->d.trapezoid.y_1;
377
 
 
378
 
            cogl_material_set_color (solid_material, &draw_color);
379
 
            cogl_set_source (solid_material);
380
 
            cogl_path_polygon (points, 4);
381
 
            cogl_path_fill ();
382
 
          }
383
 
          break;
384
 
        }
385
 
    }
386
 
}
387
 
 
388
 
static void
389
 
_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node)
390
 
{
391
 
  if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE)
392
 
    {
393
 
      g_array_free (node->d.texture.verts, TRUE);
394
 
      if (node->d.texture.texture != COGL_INVALID_HANDLE)
395
 
        cogl_texture_unref (node->d.texture.texture);
396
 
      if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
397
 
        cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
398
 
    }
399
 
 
400
 
  g_slice_free (CoglPangoDisplayListNode, node);
401
 
}
402
 
 
403
 
void
404
 
_cogl_pango_display_list_clear (CoglPangoDisplayList *dl)
405
 
{
406
 
  g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL);
407
 
  g_slist_free (dl->nodes);
408
 
  dl->nodes = NULL;
409
 
  dl->last_node = NULL;
410
 
}
411
 
 
412
 
void
413
 
_cogl_pango_display_list_free (CoglPangoDisplayList *dl)
414
 
{
415
 
  _cogl_pango_display_list_clear (dl);
416
 
  g_slice_free (CoglPangoDisplayList, dl);
417
 
}