ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/pango-render.c
Revision: 1.1
Committed: Tue Jul 4 23:23:32 2006 UTC (17 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
Get rid of cairo completely (yay!) and of ft2 factually (still need the
library as it included pangofc), by introducing a custom pango opengl
renderer.

Text rendering now no longer requires the distinction between rgba and
grayscale modes, requires much less texture space and memory, and is
faster on accelerated hardware (and possibly with software rendering, too).

All at the cost of only 1200 lines or so.

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