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

# 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 root 1.6 int flags;
41 root 1.7 rc_t *rc; // rendercache
42     rc_key_t key; // current render key
43     rc_array_t *arr;
44 root 1.1 };
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 root 1.2 FT_Face face;
109    
110 root 1.1 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 root 1.2 face = pango_opengl_font_get_face (font);
131 root 1.1
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 root 1.3 int generation;
155 root 1.1 } 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 root 1.2 glyph_info *g;
169     float x1, y1, x2, y2;
170 root 1.1
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 root 1.2 g = _pango_opengl_font_get_cache_glyph_data (font, glyph);
180 root 1.1
181 root 1.3 if (!g || g->generation != tc_generation)
182 root 1.1 {
183     Glyph bm;
184     font_render_glyph (&bm, font, glyph);
185    
186 root 1.3 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 root 1.1
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 root 1.7 if (g->tex.name != renderer->key.texname)
213 root 1.1 {
214 root 1.7 renderer->key.texname = g->tex.name;
215     renderer->arr = rc_array (renderer->rc, &renderer->key);
216 root 1.1 }
217    
218 root 1.11 rc_glyph (renderer->arr, g->tex.x, g->tex.y, g->tex.w, g->tex.h, x, y);
219 root 1.1 }
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 root 1.7 rc_key_t key = renderer->key;
233     rc_array_t *arr;
234 root 1.1
235 root 1.7 key.mode = GL_QUADS;
236     key.format = GL_V2F;
237     key.texname = 0;
238    
239     arr = rc_array (renderer->rc, &key);
240    
241 root 1.8 rc_v2f (arr, x11, y1);
242     rc_v2f (arr, x21, y1);
243     rc_v2f (arr, x22, y2);
244     rc_v2f (arr, x12, y2);
245 root 1.1 }
246    
247     void
248     pango_opengl_render_layout_subpixel (PangoLayout *layout,
249 root 1.10 rc_t *rc,
250 root 1.1 int x, int y,
251 root 1.6 float r, float g, float b, float a,
252     int flags)
253 root 1.1 {
254     PangoContext *context;
255     PangoFontMap *fontmap;
256     PangoRenderer *renderer;
257 root 1.8 PangoOpenGLRenderer *gl;
258 root 1.1
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 root 1.8 gl = PANGO_OPENGL_RENDERER (renderer);
263 root 1.1
264 root 1.10 gl->rc = rc;
265 root 1.8 gl->r = r;
266     gl->g = g;
267     gl->b = b;
268     gl->a = a;
269     gl->flags = flags;
270 root 1.1
271     pango_renderer_draw_layout (renderer, layout, x, y);
272     }
273    
274     void
275     pango_opengl_render_layout (PangoLayout *layout,
276 root 1.10 rc_t *rc,
277 root 1.1 int x, int y,
278 root 1.6 float r, float g, float b, float a,
279     int flags)
280 root 1.1 {
281 root 1.10 pango_opengl_render_layout_subpixel (
282     layout, rc, x * PANGO_SCALE, y * PANGO_SCALE, r, g, b, a, flags
283     );
284 root 1.1 }
285    
286     static void
287     pango_opengl_renderer_init (PangoOpenGLRenderer *renderer)
288     {
289 root 1.7 memset (&renderer->key, 0, sizeof (rc_key_t));
290    
291 root 1.1 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 root 1.9 PangoOpenGLRenderer *gl = (PangoOpenGLRenderer *)renderer;
301 root 1.1 PangoColor *fg = 0;
302     GSList *l;
303 root 1.6 unsigned char r, g, b, a;
304 root 1.1
305     renderer->underline = PANGO_UNDERLINE_NONE;
306     renderer->strikethrough = FALSE;
307    
308 root 1.9 gl->key.mode = GL_QUADS;
309 root 1.11 gl->key.format = 0; // glyphs
310 root 1.9 gl->key.texname = 0;
311 root 1.7
312 root 1.1 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 root 1.6 {
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 root 1.1 else
342 root 1.6 {
343 root 1.9 r = gl->r * 255.f;
344     g = gl->g * 255.f;
345     b = gl->b * 255.f;
346 root 1.6 }
347    
348 root 1.9 a = gl->a * 255.f;
349 root 1.6
350 root 1.9 if (gl->flags & FLAG_INVERSE)
351 root 1.6 {
352     r ^= 0xffU;
353     g ^= 0xffU;
354     b ^= 0xffU;
355     }
356    
357 root 1.9 gl->key.r = r;
358     gl->key.g = g;
359     gl->key.b = b;
360     gl->key.a = a;
361 root 1.1 }
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