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

# User Rev Content
1 root 1.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