ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/pango-render.c
Revision: 1.16
Committed: Thu Nov 26 07:19:11 2009 UTC (14 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.15: +39 -8 lines
Log Message:
*** empty log message ***

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 char *apple_nvidia_bug_buf;
165
166 static void
167 apple_nvidia_bug (int enable)
168 {
169 g_slice_free1 (TC_WIDTH * TC_HEIGHT, apple_nvidia_bug_buf);
170 apple_nvidia_bug_buf = enable ? g_slice_alloc (TC_WIDTH * TC_HEIGHT) : 0;
171 }
172
173 static void
174 tex_update (int name, int x, int y, int w, int stride, int h, void *bm)
175 {
176 glBindTexture (GL_TEXTURE_2D, name);
177
178 if (!apple_nvidia_bug_buf)
179 {
180 glPixelStorei (GL_UNPACK_ROW_LENGTH, stride);
181 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
182 glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, bm);
183 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
184 glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
185 }
186 else
187 {
188 /* starting with 10.5.5 (or 10.5.6), pple's nvidia driver corrupts textures */
189 /* when glTexSubImage is used, so do it the horribly slow way, */
190 /* reading/patching/uploading the full texture one each change */
191 int r;
192
193 glGetTexImage (GL_TEXTURE_2D, 0, GL_ALPHA, GL_UNSIGNED_BYTE, apple_nvidia_bug_buf);
194
195 for (r = 0; r < h; ++r)
196 memcpy ((char *)apple_nvidia_bug_buf + (y + r) * TC_WIDTH + x, (char *)bm + r * stride, w);
197
198 glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, TC_WIDTH, TC_HEIGHT, 0, GL_ALPHA, GL_UNSIGNED_BYTE, apple_nvidia_bug_buf);
199 }
200 }
201
202 static void
203 draw_glyph (PangoRenderer *renderer_, PangoFont *font, PangoGlyph glyph, double x, double y)
204 {
205 PangoOpenGLRenderer *renderer = PANGO_OPENGL_RENDERER (renderer_);
206 glyph_info *g;
207
208 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
209 {
210 glyph = pango_opengl_get_unknown_glyph (font);
211
212 if (glyph == PANGO_GLYPH_EMPTY)
213 glyph = PANGO_GLYPH_UNKNOWN_FLAG;
214 }
215
216 g = _pango_opengl_font_get_cache_glyph_data (font, glyph);
217
218 if (!g || g->generation != tc_generation)
219 {
220 Glyph bm;
221 font_render_glyph (&bm, font, glyph);
222
223 if (!g)
224 {
225 g = g_slice_new (glyph_info);
226
227 _pango_opengl_font_set_glyph_cache_destroy (font, (GDestroyNotify)free_glyph_info);
228 _pango_opengl_font_set_cache_glyph_data (font, glyph, g);
229 }
230
231 g->generation = tc_generation;
232
233 g->left = bm.left;
234 g->top = bm.top;
235
236 tc_get (&g->tex, bm.width, bm.height);
237
238 if (bm.width && bm.height)
239 tex_update (g->tex.name, g->tex.x, g->tex.y, bm.width, bm.stride, bm.height, bm.bitmap);
240 }
241
242 x += g->left;
243 y -= g->top;
244
245 if (g->tex.name != renderer->key.texname)
246 {
247 renderer->key.texname = g->tex.name;
248 renderer->arr = rc_array (renderer->rc, &renderer->key);
249 }
250
251 rc_glyph (renderer->arr, g->tex.x, g->tex.y, g->tex.w, g->tex.h, x, y);
252 }
253
254 static void
255 draw_trapezoid (PangoRenderer *renderer_,
256 PangoRenderPart part,
257 double y1,
258 double x11,
259 double x21,
260 double y2,
261 double x12,
262 double x22)
263 {
264 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
265 rc_key_t key = renderer->key;
266 rc_array_t *arr;
267
268 key.mode = GL_QUADS;
269 key.format = GL_V2F;
270 key.texname = 0;
271
272 arr = rc_array (renderer->rc, &key);
273
274 rc_v2f (arr, x11, y1);
275 rc_v2f (arr, x21, y1);
276 rc_v2f (arr, x22, y2);
277 rc_v2f (arr, x12, y2);
278 }
279
280 void
281 pango_opengl_render_layout_subpixel (PangoLayout *layout,
282 rc_t *rc,
283 int x, int y,
284 float r, float g, float b, float a,
285 int flags)
286 {
287 PangoContext *context;
288 PangoFontMap *fontmap;
289 PangoRenderer *renderer;
290 PangoOpenGLRenderer *gl;
291
292 context = pango_layout_get_context (layout);
293 fontmap = pango_context_get_font_map (context);
294 renderer = _pango_opengl_font_map_get_renderer (PANGO_OPENGL_FONT_MAP (fontmap));
295 gl = PANGO_OPENGL_RENDERER (renderer);
296
297 gl->rc = rc;
298 gl->r = r;
299 gl->g = g;
300 gl->b = b;
301 gl->a = a;
302 gl->flags = flags;
303
304 pango_renderer_draw_layout (renderer, layout, x, y);
305 }
306
307 void
308 pango_opengl_render_layout (PangoLayout *layout,
309 rc_t *rc,
310 int x, int y,
311 float r, float g, float b, float a,
312 int flags)
313 {
314 pango_opengl_render_layout_subpixel (
315 layout, rc, x * PANGO_SCALE, y * PANGO_SCALE, r, g, b, a, flags
316 );
317 }
318
319 static void
320 pango_opengl_renderer_init (PangoOpenGLRenderer *renderer)
321 {
322 memset (&renderer->key, 0, sizeof (rc_key_t));
323
324 renderer->r = 1.;
325 renderer->g = 1.;
326 renderer->b = 1.;
327 renderer->a = 1.;
328 }
329
330 static void
331 prepare_run (PangoRenderer *renderer, PangoLayoutRun *run)
332 {
333 PangoOpenGLRenderer *gl = (PangoOpenGLRenderer *)renderer;
334 PangoColor *fg = 0;
335 GSList *l;
336 unsigned char r, g, b, a;
337
338 renderer->underline = PANGO_UNDERLINE_NONE;
339 renderer->strikethrough = FALSE;
340
341 gl->key.mode = GL_QUADS;
342 gl->key.format = 0; // glyphs
343 gl->key.texname = 0;
344
345 for (l = run->item->analysis.extra_attrs; l; l = l->next)
346 {
347 PangoAttribute *attr = l->data;
348
349 switch (attr->klass->type)
350 {
351 case PANGO_ATTR_UNDERLINE:
352 renderer->underline = ((PangoAttrInt *)attr)->value;
353 break;
354
355 case PANGO_ATTR_STRIKETHROUGH:
356 renderer->strikethrough = ((PangoAttrInt *)attr)->value;
357 break;
358
359 case PANGO_ATTR_FOREGROUND:
360 fg = &((PangoAttrColor *)attr)->color;
361 break;
362
363 default:
364 break;
365 }
366 }
367
368 if (fg)
369 {
370 r = fg->red * (255.f / 65535.f);
371 g = fg->green * (255.f / 65535.f);
372 b = fg->blue * (255.f / 65535.f);
373 }
374 else
375 {
376 r = gl->r * 255.f;
377 g = gl->g * 255.f;
378 b = gl->b * 255.f;
379 }
380
381 a = gl->a * 255.f;
382
383 if (gl->flags & FLAG_INVERSE)
384 {
385 r ^= 0xffU;
386 g ^= 0xffU;
387 b ^= 0xffU;
388 }
389
390 gl->key.r = r;
391 gl->key.g = g;
392 gl->key.b = b;
393 gl->key.a = a;
394 }
395
396 static void
397 draw_begin (PangoRenderer *renderer_)
398 {
399 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
400 }
401
402 static void
403 draw_end (PangoRenderer *renderer_)
404 {
405 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
406 }
407
408 static void
409 pango_opengl_renderer_class_init (PangoOpenGLRendererClass *klass)
410 {
411 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
412
413 renderer_class->draw_glyph = draw_glyph;
414 renderer_class->draw_trapezoid = draw_trapezoid;
415 renderer_class->prepare_run = prepare_run;
416 renderer_class->begin = draw_begin;
417 renderer_class->end = draw_end;
418 }
419