4
* An OpenGL based 'interactive canvas' library.
6
* Authored By Neil Roberts <neil@linux.intel.com>
8
* Copyright (C) 2009 Intel Corporation.
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.
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.
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/>.
29
#include <cogl/cogl.h>
32
#include "cogl-pango-display-list.h"
36
COGL_PANGO_DISPLAY_LIST_TEXTURE,
37
COGL_PANGO_DISPLAY_LIST_RECTANGLE,
38
COGL_PANGO_DISPLAY_LIST_TRAPEZOID
39
} CoglPangoDisplayListNodeType;
41
typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode;
42
typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex;
44
struct _CoglPangoDisplayList
46
gboolean color_override;
52
struct _CoglPangoDisplayListNode
54
CoglPangoDisplayListNodeType type;
56
gboolean color_override;
63
/* The texture to render these coords from */
65
/* Array of vertex data to render out of this texture */
67
/* A VBO representing those vertices */
68
CoglHandle vertex_buffer;
89
struct _CoglPangoDisplayListVertex
94
CoglPangoDisplayList *
95
_cogl_pango_display_list_new (void)
97
return g_slice_new0 (CoglPangoDisplayList);
101
_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl,
102
CoglPangoDisplayListNode *node)
105
dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node);
107
dl->last_node = dl->nodes = g_slist_prepend (NULL, node);
111
_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl,
112
const CoglColor *color)
114
dl->color_override = TRUE;
119
_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl)
121
dl->color_override = FALSE;
125
_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
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)
132
CoglPangoDisplayListNode *node;
133
CoglPangoDisplayListVertex *verts;
135
/* Add to the last node if it is a texture node with the same
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))
144
/* Get rid of the vertex buffer so that it will be recreated */
145
if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
147
cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
148
node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
153
/* Otherwise create a new node */
154
node = g_slice_new (CoglPangoDisplayListNode);
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;
164
_cogl_pango_display_list_append_node (dl, node);
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);
195
_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
196
float x_1, float y_1,
197
float x_2, float y_2)
199
CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
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;
209
_cogl_pango_display_list_append_node (dl, node);
213
_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
221
CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
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;
233
_cogl_pango_display_list_append_node (dl, node);
237
_cogl_pango_display_list_render_texture (CoglHandle material,
238
const CoglColor *color,
239
CoglPangoDisplayListNode *node)
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);
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)
255
for (i = 0; i < node->d.texture.verts->len; i += 4)
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,
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... */
279
if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE)
281
CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len);
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,
294
cogl_vertex_buffer_submit (vb);
296
node->d.texture.vertex_buffer = vb;
300
#ifdef CLUTTER_COGL_HAS_GL
302
cogl_vertex_buffer_draw (node->d.texture.vertex_buffer,
304
0, node->d.texture.verts->len);
306
#else /* CLUTTER_COGL_HAS_GL */
308
/* GLES doesn't support GL_QUADS so instead we use a VBO with
309
indexed vertices to generate GL_TRIANGLES from the quads */
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);
315
cogl_vertex_buffer_draw_elements (node->d.texture.vertex_buffer,
316
COGL_VERTICES_MODE_TRIANGLES,
318
0, node->d.texture.verts->len - 1,
321
#endif /* CLUTTER_COGL_HAS_GL */
325
_cogl_pango_display_list_render (CoglPangoDisplayList *dl,
326
const CoglColor *color,
327
CoglHandle glyph_material,
328
CoglHandle solid_material)
332
for (l = dl->nodes; l; l = l->next)
334
CoglPangoDisplayListNode *node = l->data;
335
CoglColor draw_color;
337
if (node->color_override)
338
/* Use the override color but preserve the alpha from the
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));
347
cogl_color_premultiply (&draw_color);
351
case COGL_PANGO_DISPLAY_LIST_TEXTURE:
352
_cogl_pango_display_list_render_texture (glyph_material,
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);
365
case COGL_PANGO_DISPLAY_LIST_TRAPEZOID:
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;
378
cogl_material_set_color (solid_material, &draw_color);
379
cogl_set_source (solid_material);
380
cogl_path_polygon (points, 4);
389
_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node)
391
if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE)
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);
400
g_slice_free (CoglPangoDisplayListNode, node);
404
_cogl_pango_display_list_clear (CoglPangoDisplayList *dl)
406
g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL);
407
g_slist_free (dl->nodes);
409
dl->last_node = NULL;
413
_cogl_pango_display_list_free (CoglPangoDisplayList *dl)
415
_cogl_pango_display_list_clear (dl);
416
g_slice_free (CoglPangoDisplayList, dl);