svn merge -r 21041:21243 https://svn.blender.org/svnroot/bf-blender/branches/blender2...
[blender.git] / source / blender / blenfont / intern / blf_glyph.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33
34 #include <ft2build.h>
35
36 #include FT_FREETYPE_H
37 #include FT_GLYPH_H
38 #include FT_OUTLINE_H
39
40 #include "MEM_guardedalloc.h"
41
42 #include "DNA_listBase.h"
43 #include "DNA_vec_types.h"
44
45 #include "BKE_utildefines.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_linklist.h"       /* linknode */
49 #include "BLI_string.h"
50
51 #include "BIF_gl.h"
52 #include "BLF_api.h"
53
54 #include "blf_internal_types.h"
55 #include "blf_internal.h"
56
57
58 GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, int size, int dpi)
59 {
60         GlyphCacheBLF *p;
61
62         p= (GlyphCacheBLF *)font->cache.first;
63         while (p) {
64                 if (p->size == size && p->dpi == dpi)
65                         return(p);
66                 p= p->next;
67         }
68         return(NULL);
69 }
70
71 /* Create a new glyph cache for the current size and dpi. */
72 GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
73 {
74         GlyphCacheBLF *gc;
75         int i;
76
77         gc= (GlyphCacheBLF *)MEM_mallocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new");
78         gc->next= NULL;
79         gc->prev= NULL;
80         gc->size= font->size;
81         gc->dpi= font->dpi;
82
83         for (i= 0; i < 257; i++) {
84                 gc->bucket[i].first= NULL;
85                 gc->bucket[i].last= NULL;
86         }
87
88         gc->textures= (GLuint *)malloc(sizeof(GLuint)*256);
89         gc->ntex= 256;
90         gc->cur_tex= -1;
91         gc->x_offs= 0;
92         gc->y_offs= 0;
93         gc->pad= 3;
94
95         gc->num_glyphs= font->face->num_glyphs;
96         gc->rem_glyphs= font->face->num_glyphs;
97         gc->ascender= ((float)font->face->size->metrics.ascender) / 64.0f;
98         gc->descender= ((float)font->face->size->metrics.descender) / 64.0f;
99
100         if (FT_IS_SCALABLE(font->face)) {
101                 gc->max_glyph_width= (float)((font->face->bbox.xMax - font->face->bbox.xMin) *
102                                         (((float)font->face->size->metrics.x_ppem) /
103                                          ((float)font->face->units_per_EM)));
104
105                 gc->max_glyph_height= (float)((font->face->bbox.yMax - font->face->bbox.yMin) *
106                                         (((float)font->face->size->metrics.y_ppem) /
107                                          ((float)font->face->units_per_EM)));
108         }
109         else {
110                 gc->max_glyph_width= ((float)font->face->size->metrics.max_advance) / 64.0f;
111                 gc->max_glyph_height= ((float)font->face->size->metrics.height) / 64.0f;
112         }
113
114         gc->p2_width= 0;
115         gc->p2_height= 0;
116
117         BLI_addhead(&font->cache, gc);
118         return(gc);
119 }
120
121 void blf_glyph_cache_free(GlyphCacheBLF *gc)
122 {
123         GlyphBLF *g;
124         int i;
125
126         for (i= 0; i < 257; i++) {
127                 while (gc->bucket[i].first) {
128                         g= gc->bucket[i].first;
129                         BLI_remlink(&(gc->bucket[i]), g);
130                         blf_glyph_free(g);
131                 }
132         }
133
134         glDeleteTextures(gc->cur_tex+1, gc->textures);
135         free((void *)gc->textures);
136         MEM_freeN(gc);
137 }
138
139 void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
140 {
141         int tot_mem, i;
142         unsigned char *buf;
143
144         /* move the index. */
145         gc->cur_tex++;
146
147         if (gc->cur_tex >= gc->ntex) {
148                 gc->ntex *= 2;
149                 gc->textures= (GLuint *)realloc((void *)gc->textures, sizeof(GLuint)*gc->ntex);
150         }
151
152         gc->p2_width= blf_next_p2((gc->rem_glyphs * gc->max_glyph_width) + (gc->pad * 2));
153         if (gc->p2_width > font->max_tex_size)
154                 gc->p2_width= font->max_tex_size;
155
156         i= (int)((gc->p2_width - (gc->pad * 2)) / gc->max_glyph_width);
157         gc->p2_height= blf_next_p2(((gc->num_glyphs / i) + 1) * gc->max_glyph_height);
158
159         if (gc->p2_height > font->max_tex_size)
160                 gc->p2_height= font->max_tex_size;
161
162         tot_mem= gc->p2_width * gc->p2_height;
163         buf= (unsigned char *)malloc(tot_mem);
164         memset((void *)buf, 0, tot_mem);
165
166         glGenTextures(1, &gc->textures[gc->cur_tex]);
167         glBindTexture(GL_TEXTURE_2D, gc->textures[gc->cur_tex]);
168         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
169         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
170         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
171         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
172
173         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf);
174         free((void *)buf);
175 }
176
177 GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
178 {
179         GlyphBLF *p;
180         unsigned int key;
181
182         key= blf_hash(c);
183         p= gc->bucket[key].first;
184         while (p) {
185                 if (p->c == c)
186                         return(p);
187                 p= p->next;
188         }
189         return(NULL);
190 }
191
192 GlyphBLF *blf_glyph_texture_add(FontBLF *font, FT_UInt index, unsigned int c)
193 {
194         FT_GlyphSlot slot;
195         GlyphCacheBLF *gc;
196         GlyphBLF *g;
197         GlyphTextureBLF *gt;
198         FT_Error err;
199         FT_Bitmap bitmap;
200         FT_BBox bbox;
201         unsigned int key;
202         int do_new;
203
204         g= blf_glyph_search(font->glyph_cache, c);
205
206         /* The glyph can be add on Bitmap mode, so we have the
207          * glyph, but not the texture data.
208          */
209         if (g && g->tex_data)
210                 return(g);
211         else if (g)
212                 do_new= 0;
213         else
214                 do_new= 1;
215
216         if (font->flags & BLF_FONT_KERNING)
217                 err= FT_Load_Glyph(font->face, index, FT_LOAD_NO_BITMAP);
218         else
219                 err= FT_Load_Glyph(font->face, index, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
220
221         if (err)
222                 return(NULL);
223
224         /* get the glyph. */
225         slot= font->face->glyph;
226
227         err= FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
228         if (err || slot->format != FT_GLYPH_FORMAT_BITMAP)
229                 return(NULL);
230
231         if (do_new) {
232                 g= (GlyphBLF *)MEM_mallocN(sizeof(GlyphBLF), "blf_glyph_add");
233                 g->next= NULL;
234                 g->prev= NULL;
235                 g->tex_data= NULL;
236                 g->bitmap_data= NULL;
237                 g->c= c;
238         }
239
240         gt= (GlyphTextureBLF *)MEM_mallocN(sizeof(GlyphTextureBLF), "blf_glyph_texture_add");
241         gc= font->glyph_cache;
242
243         if (gc->cur_tex == -1) {
244                 blf_glyph_cache_texture(font, gc);
245                 gc->x_offs= gc->pad;
246                 gc->y_offs= gc->pad;
247         }
248
249         if (gc->x_offs > (gc->p2_width - gc->max_glyph_width)) {
250                 gc->x_offs= gc->pad;
251                 gc->y_offs += gc->max_glyph_height;
252
253                 if (gc->y_offs > (gc->p2_height - gc->max_glyph_height)) {
254                         gc->y_offs= gc->pad;
255                         blf_glyph_cache_texture(font, gc);
256                 }
257         }
258
259         bitmap= slot->bitmap;
260         gt->tex= gc->textures[gc->cur_tex];
261
262         gt->xoff= gc->x_offs;
263         gt->yoff= gc->y_offs;
264         gt->width= bitmap.width;
265         gt->height= bitmap.rows;
266
267         if (gt->width && gt->height) {
268                 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
269                 glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
270                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
271                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
272
273                 glBindTexture(GL_TEXTURE_2D, gt->tex);
274                 glTexSubImage2D(GL_TEXTURE_2D, 0, gt->xoff, gt->yoff, gt->width, gt->height, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer);
275                 glPopClientAttrib();
276         }
277
278         g->advance= ((float)slot->advance.x) / 64.0f;
279         gt->pos_x= slot->bitmap_left;
280         gt->pos_y= slot->bitmap_top;
281
282         FT_Outline_Get_CBox(&(slot->outline), &bbox);
283         g->box.xmin= ((float)bbox.xMin) / 64.0f;
284         g->box.xmax= ((float)bbox.xMax) / 64.0f;
285         g->box.ymin= ((float)bbox.yMin) / 64.0f;
286         g->box.ymax= ((float)bbox.yMax) / 64.0f;
287
288         gt->uv[0][0]= ((float)gt->xoff) / ((float)gc->p2_width);
289         gt->uv[0][1]= ((float)gt->yoff) / ((float)gc->p2_height);
290         gt->uv[1][0]= ((float)(gt->xoff + gt->width)) / ((float)gc->p2_width);
291         gt->uv[1][1]= ((float)(gt->yoff + gt->height)) / ((float)gc->p2_height);
292
293         /* update the x offset for the next glyph. */
294         gc->x_offs += (int)(g->box.xmax - g->box.xmin + gc->pad);
295
296         if (do_new) {
297                 key= blf_hash(g->c);
298                 BLI_addhead(&(gc->bucket[key]), g);
299                 gc->rem_glyphs--;
300         }
301
302         /* and attach the texture information. */
303         g->tex_data= gt;
304
305         return(g);
306 }
307
308 GlyphBLF *blf_glyph_bitmap_add(FontBLF *font, FT_UInt index, unsigned int c)
309 {
310         FT_GlyphSlot slot;
311         GlyphCacheBLF *gc;
312         GlyphBLF *g;
313         GlyphBitmapBLF *gt;
314         FT_Error err;
315         FT_Bitmap bitmap;
316         FT_BBox bbox;
317         unsigned char *dest, *src;
318         unsigned int key, y;
319         unsigned int src_width, src_height, src_pitch;
320         int do_new;
321
322         g= blf_glyph_search(font->glyph_cache, c);
323
324         /*
325          * The glyph can be add on Texture mode, so we have the
326          * glyph, but not the bitmap data.
327          */
328         if (g && g->bitmap_data)
329                 return(g);
330         else if (g)
331                 do_new= 0;
332         else
333                 do_new= 1;
334
335         if (font->flags & BLF_FONT_KERNING)
336                 err= FT_Load_Glyph(font->face, index, FT_LOAD_NO_BITMAP);
337         else
338                 err= FT_Load_Glyph(font->face, index, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
339
340         if (err)
341                 return(NULL);
342
343         /* get the glyph. */
344         slot= font->face->glyph;
345
346         err= FT_Render_Glyph(slot, FT_RENDER_MODE_MONO);
347         if (err || slot->format != FT_GLYPH_FORMAT_BITMAP)
348                 return(NULL);
349
350         if (do_new) {
351                 g= (GlyphBLF *)MEM_mallocN(sizeof(GlyphBLF), "blf_glyph_add");
352                 g->next= NULL;
353                 g->prev= NULL;
354                 g->tex_data= NULL;
355                 g->bitmap_data= NULL;
356                 g->c= c;
357         }
358
359         gt= (GlyphBitmapBLF *)MEM_mallocN(sizeof(GlyphBitmapBLF), "blf_glyph_bitmap_add");
360         gc= font->glyph_cache;
361
362         bitmap= slot->bitmap;
363
364         src_width= bitmap.width;
365         src_height= bitmap.rows;
366         src_pitch= bitmap.pitch;
367
368         gt->width= src_width;
369         gt->height= src_height;
370         gt->pitch= src_pitch;
371         gt->image= NULL;
372
373         if (gt->width && gt->height) {
374                 gt->image= (unsigned char *)malloc(gt->pitch * gt->height);
375
376                 dest= gt->image + ((gt->height - 1) * gt->pitch);
377                 src= bitmap.buffer;
378
379                 for (y= 0; y < src_height; ++y) {
380                         memcpy((void *)dest, (void *)src, src_pitch);
381                         dest -= gt->pitch;
382                         src += src_pitch;
383                 }
384         }
385
386         g->advance= ((float)slot->advance.x) / 64.0f;
387         gt->pos_x= slot->bitmap_left;
388         gt->pos_y= ((int)src_height) - slot->bitmap_top;
389
390         FT_Outline_Get_CBox(&(slot->outline), &bbox);
391         g->box.xmin= ((float)bbox.xMin) / 64.0f;
392         g->box.xmax= ((float)bbox.xMax) / 64.0f;
393         g->box.ymin= ((float)bbox.yMin) / 64.0f;
394         g->box.ymax= ((float)bbox.yMax) / 64.0f;
395
396         if (do_new) {
397                 key= blf_hash(g->c);
398                 BLI_addhead(&(gc->bucket[key]), g);
399                 gc->rem_glyphs--;
400         }
401
402         /* and attach the bitmap information. */
403         g->bitmap_data= gt;
404
405         return(g);
406 }
407
408 GlyphBLF *blf_glyph_add(FontBLF *font, FT_UInt index, unsigned int c)
409 {
410         if (font->mode == BLF_MODE_BITMAP)
411                 return(blf_glyph_bitmap_add(font, index, c));
412         return(blf_glyph_texture_add(font, index, c));
413 }
414
415 void blf_glyph_free(GlyphBLF *g)
416 {
417         if (g->tex_data)
418                 MEM_freeN(g->tex_data);
419
420         if (g->bitmap_data) {
421                 if (g->bitmap_data->image)
422                         free((void *)g->bitmap_data->image);
423                 MEM_freeN(g->bitmap_data);
424         }
425
426         /* don't need free the texture, the GlyphCache already
427          * have a list of all the texture and free it.
428          */
429         MEM_freeN(g);
430 }
431
432 static void blf_texture_draw(float uv[2][2], float dx, float y1, float dx1, float y2)
433 {
434         
435         glBegin(GL_QUADS);
436         glTexCoord2f(uv[0][0], uv[0][1]);
437         glVertex2f(dx, y1);
438         
439         glTexCoord2f(uv[0][0], uv[1][1]);
440         glVertex2f(dx, y2);
441         
442         glTexCoord2f(uv[1][0], uv[1][1]);
443         glVertex2f(dx1, y2);
444         
445         glTexCoord2f(uv[1][0], uv[0][1]);
446         glVertex2f(dx1, y1);
447         glEnd();
448         
449 }
450
451 static void blf_texture5_draw(float uv[2][2], float x1, float y1, float x2, float y2)
452 {
453         float soft[25]= {
454                 1/60.0f, 1/60.0f, 2/60.0f, 1/60.0f, 1/60.0f, 
455                 1/60.0f, 3/60.0f, 5/60.0f, 3/60.0f, 1/60.0f, 
456                 2/60.0f, 5/60.0f, 8/60.0f, 5/60.0f, 2/60.0f, 
457                 1/60.0f, 3/60.0f, 5/60.0f, 3/60.0f, 1/60.0f, 
458                 1/60.0f, 1/60.0f, 2/60.0f, 1/60.0f, 1/60.0f};
459         
460         float color[4], *fp= soft;
461         int dx, dy;
462         
463         glGetFloatv(GL_CURRENT_COLOR, color);
464         
465         for(dx=-2; dx<3; dx++) {
466                 for(dy=-2; dy<3; dy++, fp++) {
467                         glColor4f(color[0], color[1], color[2], fp[0]*color[3]);
468                         blf_texture_draw(uv, x1+dx, y1+dy, x2+dx, y2+dy);
469                 }
470         }
471         
472         glColor4fv(color);
473 }
474
475 static void blf_texture3_draw(float uv[2][2], float x1, float y1, float x2, float y2)
476 {
477         float soft[9]= {1/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 4/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 1/16.0f};
478         float color[4], *fp= soft;
479         int dx, dy;
480         
481         glGetFloatv(GL_CURRENT_COLOR, color);
482         
483         for(dx=-1; dx<2; dx++) {
484                 for(dy=-1; dy<2; dy++, fp++) {
485                         glColor4f(color[0], color[1], color[2], fp[0]*color[3]);
486                         blf_texture_draw(uv, x1+dx, y1+dy, x2+dx, y2+dy);
487                 }
488         }
489         
490         glColor4fv(color);
491 }
492
493 int blf_glyph_texture_render(FontBLF *font, GlyphBLF *g, float x, float y)
494 {
495         GlyphTextureBLF *gt;
496         GLint cur_tex;
497         float dx, dx1;
498         float y1, y2;
499         float xo, yo;
500         float color[4];
501
502         gt= g->tex_data;
503         xo= 0.0f;
504         yo= 0.0f;
505
506         if (font->flags & BLF_SHADOW) {
507                 xo= x;
508                 yo= y;
509                 x += font->shadow_x;
510                 y += font->shadow_y;
511         }
512
513         dx= floor(x + gt->pos_x);
514         dx1= dx + gt->width;
515         y1= y + gt->pos_y;
516         y2= y + gt->pos_y - gt->height;
517
518         if (font->flags & BLF_CLIPPING) {
519                 if (!BLI_in_rctf(&font->clip_rec, dx + font->pos[0], y1 + font->pos[1]))
520                         return(0);
521                 if (!BLI_in_rctf(&font->clip_rec, dx + font->pos[0], y2 + font->pos[1]))
522                         return(0);
523                 if (!BLI_in_rctf(&font->clip_rec, dx1 + font->pos[0], y2 + font->pos[1]))
524                         return(0);
525                 if (!BLI_in_rctf(&font->clip_rec, dx1 + font->pos[0], y1 + font->pos[1]))
526                         return(0);
527         }
528
529         glGetIntegerv(GL_TEXTURE_2D_BINDING_EXT, &cur_tex);
530         if (cur_tex != gt->tex)
531                 glBindTexture(GL_TEXTURE_2D, gt->tex);
532
533         if (font->flags & BLF_SHADOW) {
534                 glGetFloatv(GL_CURRENT_COLOR, color);
535                 glColor4fv(font->shadow_col);
536
537                 if (font->shadow == 3)
538                         blf_texture3_draw(gt->uv, dx, y1, dx1, y2);
539                 else if (font->shadow == 5)
540                         blf_texture5_draw(gt->uv, dx, y1, dx1, y2);
541                 else
542                         blf_texture_draw(gt->uv, dx, y1, dx1, y2);
543
544                 glColor4fv(color);
545                 x= xo;
546                 y= yo;
547
548                 dx= floor(x + gt->pos_x);
549                 dx1= dx + gt->width;
550                 y1= y + gt->pos_y;
551                 y2= y + gt->pos_y - gt->height;
552         }
553
554         if (font->blur==3)
555                 blf_texture3_draw(gt->uv, dx, y1, dx1, y2);
556         else if (font->blur==5)
557                 blf_texture5_draw(gt->uv, dx, y1, dx1, y2);
558         else
559                 blf_texture_draw(gt->uv, dx, y1, dx1, y2);
560         
561         return(1);
562 }
563
564 int blf_glyph_bitmap_render(FontBLF *font, GlyphBLF *g, float x, float y)
565 {
566         GlyphBitmapBLF *gt;
567         GLubyte null_bitmap= 0;
568
569         gt= g->bitmap_data;
570         if (!gt->image)
571                 return(1);
572
573         if (font->flags & BLF_CLIPPING) {
574                 if (!BLI_in_rctf(&font->clip_rec, x + font->pos[0], y + font->pos[1]))
575                         return(0);
576                 if (!BLI_in_rctf(&font->clip_rec, x + font->pos[0], y + gt->height + font->pos[1]))
577                         return(0);
578                 if (!BLI_in_rctf(&font->clip_rec, x + gt->width + font->pos[0], y + gt->height + font->pos[1]))
579                         return(0);
580                 if (!BLI_in_rctf(&font->clip_rec, x + gt->width + font->pos[0], y + font->pos[1]))
581                         return(0);
582         }
583
584         glBitmap(0, 0, 0.0, 0.0, x + font->pos[0], y - font->pos[1], (const GLubyte *)&null_bitmap);
585         glPixelStorei(GL_UNPACK_ROW_LENGTH, gt->pitch * 8);
586         glBitmap(gt->width, gt->height, 0.0, gt->pos_y, 0.0, 0.0, (const GLubyte *)gt->image);
587         glBitmap(0, 0, 0.0, 0.0, -x - font->pos[0], -y + font->pos[1], (const GLubyte *)&null_bitmap);
588         return(1);
589 }
590
591 int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
592 {
593         if (font->mode == BLF_MODE_BITMAP)
594                 return(blf_glyph_bitmap_render(font, g, x, y));
595         return(blf_glyph_texture_render(font, g, x, y));
596 }