ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/pango-render.c
Revision: 1.11
Committed: Sun Aug 12 08:44:22 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.10: +2 -10 lines
Log Message:
use an compressed format for glyph quad vectors. this reduces
the size of e.g. the opengl info from 200k to 20k, and typical
sizes for labels are now <<100 bytes. the cost is full immediate
mode submission of coordinates (cpu), but glInterleavedArrays is
likely not much faster and modern cpus probably prefer more decoding
over more cache misses.

File Contents

# Content
1 /* Pango
2 * Rendering routines to OpenGL
3 *
4 * Copyright (C) 2006 Marc Lehmann <pcg@goof.com>
5 * Copyright (C) 2004 Red Hat Software
6 * Copyright (C) 2000 Tor Lillqvist
7 *
8 * This file is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library 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 file 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 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library 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 #include <math.h>
25
26 #include "pangoopengl.h"
27
28 #define PANGO_OPENGL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_OPENGL_RENDERER, PangoOpenGLRendererClass))
29 #define PANGO_IS_OPENGL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_OPENGL_RENDERER))
30 #define PANGO_OPENGL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_OPENGL_RENDERER, PangoOpenGLRendererClass))
31
32 typedef struct {
33 PangoRendererClass parent_class;
34 } PangoOpenGLRendererClass;
35
36 struct _PangoOpenGLRenderer
37 {
38 PangoRenderer parent_instance;
39 float r, g, b, a; // modulate
40 int flags;
41 rc_t *rc; // rendercache
42 rc_key_t key; // current render key
43 rc_array_t *arr;
44 };
45
46 G_DEFINE_TYPE (PangoOpenGLRenderer, pango_opengl_renderer, PANGO_TYPE_RENDERER)
47
48 typedef struct
49 {
50 uint8_t *bitmap;
51 int width, stride, height, top, left;
52 } Glyph;
53
54 static void *
55 temp_buffer (size_t size)
56 {
57 static char *buffer;
58 static size_t alloc;
59
60 if (size > alloc)
61 {
62 size = (size + 4095) & ~4095;
63 free (buffer);
64 alloc = size;
65 buffer = malloc (size);
66 }
67
68 return buffer;
69 }
70
71 static void
72 render_box (Glyph *glyph, int width, int height, int top)
73 {
74 int i;
75 int left = 0;
76
77 if (height > 2)
78 {
79 height -= 2;
80 top++;
81 }
82
83 if (width > 2)
84 {
85 width -= 2;
86 left++;
87 }
88
89 glyph->stride = (width + 3) & ~3;
90 glyph->width = width;
91 glyph->height = height;
92 glyph->top = top;
93 glyph->left = left;
94
95 glyph->bitmap = temp_buffer (width * height);
96 memset (glyph->bitmap, 0, glyph->stride * height);
97
98 for (i = width; i--; )
99 glyph->bitmap [i] = glyph->bitmap [i + (height - 1) * glyph->stride] = 0xff;
100
101 for (i = height; i--; )
102 glyph->bitmap [i * glyph->stride] = glyph->bitmap [i * glyph->stride + (width - 1)] = 0xff;
103 }
104
105 static void
106 font_render_glyph (Glyph *glyph, PangoFont *font, int glyph_index)
107 {
108 FT_Face face;
109
110 if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG)
111 {
112 PangoFontMetrics *metrics;
113
114 if (!font)
115 goto generic_box;
116
117 metrics = pango_font_get_metrics (font, NULL);
118 if (!metrics)
119 goto generic_box;
120
121 render_box (glyph, PANGO_PIXELS (metrics->approximate_char_width),
122 PANGO_PIXELS (metrics->ascent + metrics->descent),
123 PANGO_PIXELS (metrics->ascent));
124
125 pango_font_metrics_unref (metrics);
126
127 return;
128 }
129
130 face = pango_opengl_font_get_face (font);
131
132 if (face)
133 {
134 PangoOpenGLFont *glfont = (PangoOpenGLFont *)font;
135
136 FT_Load_Glyph (face, glyph_index, glfont->load_flags);
137 FT_Render_Glyph (face->glyph, ft_render_mode_normal);
138
139 glyph->width = face->glyph->bitmap.width;
140 glyph->stride = face->glyph->bitmap.pitch;
141 glyph->height = face->glyph->bitmap.rows;
142 glyph->top = face->glyph->bitmap_top;
143 glyph->left = face->glyph->bitmap_left;
144 glyph->bitmap = face->glyph->bitmap.buffer;
145 }
146 else
147 generic_box:
148 render_box (glyph, PANGO_UNKNOWN_GLYPH_WIDTH, PANGO_UNKNOWN_GLYPH_HEIGHT, PANGO_UNKNOWN_GLYPH_HEIGHT);
149 }
150
151 typedef struct glyph_info {
152 tc_area tex;
153 int left, top;
154 int generation;
155 } glyph_info;
156
157 static void
158 free_glyph_info (glyph_info *g)
159 {
160 tc_put (&g->tex);
161 g_slice_free (glyph_info, g);
162 }
163
164 static void
165 draw_glyph (PangoRenderer *renderer_, PangoFont *font, PangoGlyph glyph, double x, double y)
166 {
167 PangoOpenGLRenderer *renderer = PANGO_OPENGL_RENDERER (renderer_);
168 glyph_info *g;
169 float x1, y1, x2, y2;
170
171 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
172 {
173 glyph = pango_opengl_get_unknown_glyph (font);
174
175 if (glyph == PANGO_GLYPH_EMPTY)
176 glyph = PANGO_GLYPH_UNKNOWN_FLAG;
177 }
178
179 g = _pango_opengl_font_get_cache_glyph_data (font, glyph);
180
181 if (!g || g->generation != tc_generation)
182 {
183 Glyph bm;
184 font_render_glyph (&bm, font, glyph);
185
186 if (g)
187 g->generation = tc_generation;
188 else
189 {
190 g = g_slice_new (glyph_info);
191
192 _pango_opengl_font_set_glyph_cache_destroy (font, (GDestroyNotify)free_glyph_info);
193 _pango_opengl_font_set_cache_glyph_data (font, glyph, g);
194 }
195
196 tc_get (&g->tex, bm.width, bm.height);
197
198 g->left = bm.left;
199 g->top = bm.top;
200
201 glBindTexture (GL_TEXTURE_2D, g->tex.name);
202 glPixelStorei (GL_UNPACK_ROW_LENGTH, bm.stride);
203 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
204 glTexSubImage2D (GL_TEXTURE_2D, 0, g->tex.x, g->tex.y, bm.width, bm.height, GL_ALPHA, GL_UNSIGNED_BYTE, bm.bitmap);
205 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
206 glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
207 }
208
209 x += g->left;
210 y -= g->top;
211
212 if (g->tex.name != renderer->key.texname)
213 {
214 renderer->key.texname = g->tex.name;
215 renderer->arr = rc_array (renderer->rc, &renderer->key);
216 }
217
218 rc_glyph (renderer->arr, g->tex.x, g->tex.y, g->tex.w, g->tex.h, x, y);
219 }
220
221 static void
222 draw_trapezoid (PangoRenderer *renderer_,
223 PangoRenderPart part,
224 double y1,
225 double x11,
226 double x21,
227 double y2,
228 double x12,
229 double x22)
230 {
231 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
232 rc_key_t key = renderer->key;
233 rc_array_t *arr;
234
235 key.mode = GL_QUADS;
236 key.format = GL_V2F;
237 key.texname = 0;
238
239 arr = rc_array (renderer->rc, &key);
240
241 rc_v2f (arr, x11, y1);
242 rc_v2f (arr, x21, y1);
243 rc_v2f (arr, x22, y2);
244 rc_v2f (arr, x12, y2);
245 }
246
247 void
248 pango_opengl_render_layout_subpixel (PangoLayout *layout,
249 rc_t *rc,
250 int x, int y,
251 float r, float g, float b, float a,
252 int flags)
253 {
254 PangoContext *context;
255 PangoFontMap *fontmap;
256 PangoRenderer *renderer;
257 PangoOpenGLRenderer *gl;
258
259 context = pango_layout_get_context (layout);
260 fontmap = pango_context_get_font_map (context);
261 renderer = _pango_opengl_font_map_get_renderer (PANGO_OPENGL_FONT_MAP (fontmap));
262 gl = PANGO_OPENGL_RENDERER (renderer);
263
264 gl->rc = rc;
265 gl->r = r;
266 gl->g = g;
267 gl->b = b;
268 gl->a = a;
269 gl->flags = flags;
270
271 pango_renderer_draw_layout (renderer, layout, x, y);
272 }
273
274 void
275 pango_opengl_render_layout (PangoLayout *layout,
276 rc_t *rc,
277 int x, int y,
278 float r, float g, float b, float a,
279 int flags)
280 {
281 pango_opengl_render_layout_subpixel (
282 layout, rc, x * PANGO_SCALE, y * PANGO_SCALE, r, g, b, a, flags
283 );
284 }
285
286 static void
287 pango_opengl_renderer_init (PangoOpenGLRenderer *renderer)
288 {
289 memset (&renderer->key, 0, sizeof (rc_key_t));
290
291 renderer->r = 1.;
292 renderer->g = 1.;
293 renderer->b = 1.;
294 renderer->a = 1.;
295 }
296
297 static void
298 prepare_run (PangoRenderer *renderer, PangoLayoutRun *run)
299 {
300 PangoOpenGLRenderer *gl = (PangoOpenGLRenderer *)renderer;
301 PangoColor *fg = 0;
302 GSList *l;
303 unsigned char r, g, b, a;
304
305 renderer->underline = PANGO_UNDERLINE_NONE;
306 renderer->strikethrough = FALSE;
307
308 gl->key.mode = GL_QUADS;
309 gl->key.format = 0; // glyphs
310 gl->key.texname = 0;
311
312 for (l = run->item->analysis.extra_attrs; l; l = l->next)
313 {
314 PangoAttribute *attr = l->data;
315
316 switch (attr->klass->type)
317 {
318 case PANGO_ATTR_UNDERLINE:
319 renderer->underline = ((PangoAttrInt *)attr)->value;
320 break;
321
322 case PANGO_ATTR_STRIKETHROUGH:
323 renderer->strikethrough = ((PangoAttrInt *)attr)->value;
324 break;
325
326 case PANGO_ATTR_FOREGROUND:
327 fg = &((PangoAttrColor *)attr)->color;
328 break;
329
330 default:
331 break;
332 }
333 }
334
335 if (fg)
336 {
337 r = fg->red * (255.f / 65535.f);
338 g = fg->green * (255.f / 65535.f);
339 b = fg->blue * (255.f / 65535.f);
340 }
341 else
342 {
343 r = gl->r * 255.f;
344 g = gl->g * 255.f;
345 b = gl->b * 255.f;
346 }
347
348 a = gl->a * 255.f;
349
350 if (gl->flags & FLAG_INVERSE)
351 {
352 r ^= 0xffU;
353 g ^= 0xffU;
354 b ^= 0xffU;
355 }
356
357 gl->key.r = r;
358 gl->key.g = g;
359 gl->key.b = b;
360 gl->key.a = a;
361 }
362
363 static void
364 draw_begin (PangoRenderer *renderer_)
365 {
366 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
367 }
368
369 static void
370 draw_end (PangoRenderer *renderer_)
371 {
372 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
373 }
374
375 static void
376 pango_opengl_renderer_class_init (PangoOpenGLRendererClass *klass)
377 {
378 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
379
380 renderer_class->draw_glyph = draw_glyph;
381 renderer_class->draw_trapezoid = draw_trapezoid;
382 renderer_class->prepare_run = prepare_run;
383 renderer_class->begin = draw_begin;
384 renderer_class->end = draw_end;
385 }
386