ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/pango-render.c
Revision: 1.3
Committed: Tue Jul 4 23:56:34 2006 UTC (17 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +11 -5 lines
Log Message:
There is of course no way to clear glyph caches in stupid pango, so we
have to add a generation counter to each and every glyph structure and
check it on every access.

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 GLuint curtex; // current texture
41 };
42
43 G_DEFINE_TYPE (PangoOpenGLRenderer, pango_opengl_renderer, PANGO_TYPE_RENDERER)
44
45 typedef struct
46 {
47 uint8_t *bitmap;
48 int width, stride, height, top, left;
49 } Glyph;
50
51 static void *
52 temp_buffer (size_t size)
53 {
54 static char *buffer;
55 static size_t alloc;
56
57 if (size > alloc)
58 {
59 size = (size + 4095) & ~4095;
60 free (buffer);
61 alloc = size;
62 buffer = malloc (size);
63 }
64
65 return buffer;
66 }
67
68 static void
69 render_box (Glyph *glyph, int width, int height, int top)
70 {
71 int i;
72 int left = 0;
73
74 if (height > 2)
75 {
76 height -= 2;
77 top++;
78 }
79
80 if (width > 2)
81 {
82 width -= 2;
83 left++;
84 }
85
86 glyph->stride = (width + 3) & ~3;
87 glyph->width = width;
88 glyph->height = height;
89 glyph->top = top;
90 glyph->left = left;
91
92 glyph->bitmap = temp_buffer (width * height);
93 memset (glyph->bitmap, 0, glyph->stride * height);
94
95 for (i = width; i--; )
96 glyph->bitmap [i] = glyph->bitmap [i + (height - 1) * glyph->stride] = 0xff;
97
98 for (i = height; i--; )
99 glyph->bitmap [i * glyph->stride] = glyph->bitmap [i * glyph->stride + (width - 1)] = 0xff;
100 }
101
102 static void
103 font_render_glyph (Glyph *glyph, PangoFont *font, int glyph_index)
104 {
105 FT_Face face;
106
107 if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG)
108 {
109 PangoFontMetrics *metrics;
110
111 if (!font)
112 goto generic_box;
113
114 metrics = pango_font_get_metrics (font, NULL);
115 if (!metrics)
116 goto generic_box;
117
118 render_box (glyph, PANGO_PIXELS (metrics->approximate_char_width),
119 PANGO_PIXELS (metrics->ascent + metrics->descent),
120 PANGO_PIXELS (metrics->ascent));
121
122 pango_font_metrics_unref (metrics);
123
124 return;
125 }
126
127 face = pango_opengl_font_get_face (font);
128
129 if (face)
130 {
131 PangoOpenGLFont *glfont = (PangoOpenGLFont *)font;
132
133 FT_Load_Glyph (face, glyph_index, glfont->load_flags);
134 FT_Render_Glyph (face->glyph, ft_render_mode_normal);
135
136 glyph->width = face->glyph->bitmap.width;
137 glyph->stride = face->glyph->bitmap.pitch;
138 glyph->height = face->glyph->bitmap.rows;
139 glyph->top = face->glyph->bitmap_top;
140 glyph->left = face->glyph->bitmap_left;
141 glyph->bitmap = face->glyph->bitmap.buffer;
142 }
143 else
144 generic_box:
145 render_box (glyph, PANGO_UNKNOWN_GLYPH_WIDTH, PANGO_UNKNOWN_GLYPH_HEIGHT, PANGO_UNKNOWN_GLYPH_HEIGHT);
146 }
147
148 typedef struct glyph_info {
149 tc_area tex;
150 int left, top;
151 int generation;
152 } glyph_info;
153
154 static void
155 free_glyph_info (glyph_info *g)
156 {
157 tc_put (&g->tex);
158 g_slice_free (glyph_info, g);
159 }
160
161 static void
162 draw_glyph (PangoRenderer *renderer_, PangoFont *font, PangoGlyph glyph, double x, double y)
163 {
164 PangoOpenGLRenderer *renderer = PANGO_OPENGL_RENDERER (renderer_);
165 glyph_info *g;
166 float x1, y1, x2, y2;
167
168 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
169 {
170 glyph = pango_opengl_get_unknown_glyph (font);
171
172 if (glyph == PANGO_GLYPH_EMPTY)
173 glyph = PANGO_GLYPH_UNKNOWN_FLAG;
174 }
175
176 g = _pango_opengl_font_get_cache_glyph_data (font, glyph);
177
178 if (!g || g->generation != tc_generation)
179 {
180 Glyph bm;
181 font_render_glyph (&bm, font, glyph);
182
183 if (g)
184 g->generation = tc_generation;
185 else
186 {
187 g = g_slice_new (glyph_info);
188
189 _pango_opengl_font_set_glyph_cache_destroy (font, (GDestroyNotify)free_glyph_info);
190 _pango_opengl_font_set_cache_glyph_data (font, glyph, g);
191 }
192
193 tc_get (&g->tex, bm.width, bm.height);
194
195 g->left = bm.left;
196 g->top = bm.top;
197
198 if (renderer->curtex)
199 {
200 glEnd ();
201 renderer->curtex = 0;
202 }
203
204 glBindTexture (GL_TEXTURE_2D, g->tex.name);
205 glPixelStorei (GL_UNPACK_ROW_LENGTH, bm.stride);
206 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
207 glTexSubImage2D (GL_TEXTURE_2D, 0, g->tex.x, g->tex.y, bm.width, bm.height, GL_ALPHA, GL_UNSIGNED_BYTE, bm.bitmap);
208 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
209 glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
210 }
211
212 x += g->left;
213 y -= g->top;
214
215 x1 = g->tex.x * (1. / TC_WIDTH );
216 y1 = g->tex.y * (1. / TC_HEIGHT);
217 x2 = g->tex.w * (1. / TC_WIDTH ) + x1;
218 y2 = g->tex.h * (1. / TC_HEIGHT) + y1;
219
220 if (g->tex.name != renderer->curtex)
221 {
222 if (renderer->curtex)
223 glEnd ();
224
225 glBindTexture (GL_TEXTURE_2D, g->tex.name);
226 renderer->curtex = g->tex.name;
227 glBegin (GL_QUADS);
228 }
229
230 glTexCoord2f (x1, y1); glVertex2i (x , y );
231 glTexCoord2f (x2, y1); glVertex2i (x + g->tex.w, y );
232 glTexCoord2f (x2, y2); glVertex2i (x + g->tex.w, y + g->tex.h);
233 glTexCoord2f (x1, y2); glVertex2i (x , y + g->tex.h);
234 }
235
236 static void
237 draw_trapezoid (PangoRenderer *renderer_,
238 PangoRenderPart part,
239 double y1,
240 double x11,
241 double x21,
242 double y2,
243 double x12,
244 double x22)
245 {
246 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
247
248 if (renderer->curtex)
249 {
250 glEnd ();
251 renderer->curtex = 0;
252 }
253
254 glDisable (GL_TEXTURE_2D);
255
256 glBegin (GL_QUADS);
257 glVertex2d (x11, y1);
258 glVertex2d (x12, y1);
259 glVertex2d (x22, y2);
260 glVertex2d (x21, y2);
261 glEnd ();
262
263 glEnable (GL_TEXTURE_2D);
264 }
265
266 void
267 pango_opengl_render_layout_subpixel (PangoLayout *layout,
268 int x, int y,
269 float r, float g, float b, float a)
270 {
271 PangoContext *context;
272 PangoFontMap *fontmap;
273 PangoRenderer *renderer;
274
275 context = pango_layout_get_context (layout);
276 fontmap = pango_context_get_font_map (context);
277 renderer = _pango_opengl_font_map_get_renderer (PANGO_OPENGL_FONT_MAP (fontmap));
278
279 PANGO_OPENGL_RENDERER (renderer)->r = r;
280 PANGO_OPENGL_RENDERER (renderer)->g = g;
281 PANGO_OPENGL_RENDERER (renderer)->b = b;
282 PANGO_OPENGL_RENDERER (renderer)->a = a;
283
284 pango_renderer_draw_layout (renderer, layout, x, y);
285 }
286
287 void
288 pango_opengl_render_layout (PangoLayout *layout,
289 int x, int y,
290 float r, float g, float b, float a)
291 {
292 pango_opengl_render_layout_subpixel (layout, x * PANGO_SCALE, y * PANGO_SCALE, r, g, b, a);
293 }
294
295 static void
296 pango_opengl_renderer_init (PangoOpenGLRenderer *renderer)
297 {
298 renderer->r = 1.;
299 renderer->g = 1.;
300 renderer->b = 1.;
301 renderer->a = 1.;
302 }
303
304 static void
305 prepare_run (PangoRenderer *renderer, PangoLayoutRun *run)
306 {
307 PangoOpenGLRenderer *glrenderer = (PangoOpenGLRenderer *)renderer;
308 PangoColor *fg = 0;
309 GSList *l;
310
311 renderer->underline = PANGO_UNDERLINE_NONE;
312 renderer->strikethrough = FALSE;
313
314 for (l = run->item->analysis.extra_attrs; l; l = l->next)
315 {
316 PangoAttribute *attr = l->data;
317
318 switch (attr->klass->type)
319 {
320 case PANGO_ATTR_UNDERLINE:
321 renderer->underline = ((PangoAttrInt *)attr)->value;
322 break;
323
324 case PANGO_ATTR_STRIKETHROUGH:
325 renderer->strikethrough = ((PangoAttrInt *)attr)->value;
326 break;
327
328 case PANGO_ATTR_FOREGROUND:
329 fg = &((PangoAttrColor *)attr)->color;
330 break;
331
332 default:
333 break;
334 }
335 }
336
337 if (fg)
338 glColor4f (fg->red / 65535., fg->green / 65535., fg->blue / 65535., glrenderer->a);
339 else
340 glColor4f (glrenderer->r, glrenderer->g, glrenderer->b, glrenderer->a);
341 }
342
343 static void
344 draw_begin (PangoRenderer *renderer_)
345 {
346 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
347
348 renderer->curtex = 0;
349
350 glEnable (GL_TEXTURE_2D);
351 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
352 glEnable (GL_BLEND);
353 gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
354 GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
355 glEnable (GL_ALPHA_TEST);
356 glAlphaFunc (GL_GREATER, 0.01f);
357 }
358
359 static void
360 draw_end (PangoRenderer *renderer_)
361 {
362 PangoOpenGLRenderer *renderer = (PangoOpenGLRenderer *)renderer_;
363
364 if (renderer->curtex)
365 glEnd ();
366
367 glDisable (GL_ALPHA_TEST);
368 glDisable (GL_BLEND);
369 glDisable (GL_TEXTURE_2D);
370 }
371
372 static void
373 pango_opengl_renderer_class_init (PangoOpenGLRendererClass *klass)
374 {
375 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
376
377 renderer_class->draw_glyph = draw_glyph;
378 renderer_class->draw_trapezoid = draw_trapezoid;
379 renderer_class->prepare_run = prepare_run;
380 renderer_class->begin = draw_begin;
381 renderer_class->end = draw_end;
382 }
383