825de7a62d2cec1eae92cb4d4f9a1ff4fb4f9218
[blender.git] / source / blender / blenfont / intern / blf_font.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
33 #ifdef WITH_FREETYPE2
34
35 #include <ft2build.h>
36
37 #include FT_FREETYPE_H
38 #include FT_GLYPH_H
39
40 #endif /* WITH_FREETYPE2 */
41
42 #include "MEM_guardedalloc.h"
43
44 #include "DNA_listBase.h"
45 #include "DNA_vec_types.h"
46
47 #include "BKE_utildefines.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_linklist.h"       /* linknode */
51 #include "BLI_string.h"
52 #include "BLI_arithb.h"
53
54 #include "BIF_gl.h"
55
56 #include "blf_internal_types.h"
57 #include "blf_internal.h"
58
59
60 #ifdef WITH_FREETYPE2
61
62 /* freetype2 handle. */
63 FT_Library global_ft_lib;
64
65 int blf_font_init(void)
66 {
67         return(FT_Init_FreeType(&global_ft_lib));
68 }
69
70 void blf_font_exit(void)
71 {
72         FT_Done_FreeType(global_ft_lib);
73 }
74
75 void blf_font_fill(FontBLF *font)
76 {
77         font->ref= 1;
78         font->aspect= 1.0f;
79         font->pos[0]= 0.0f;
80         font->pos[1]= 0.0f;
81         font->angle= 0.0f;
82         Mat4One(font->mat);
83         font->clip_rec.xmin= 0.0f;
84         font->clip_rec.xmax= 0.0f;
85         font->clip_rec.ymin= 0.0f;
86         font->clip_rec.ymax= 0.0f;
87         font->clip_mode= BLF_CLIP_DISABLE;
88         font->dpi= 0;
89         font->size= 0;
90         font->cache.first= NULL;
91         font->cache.last= NULL;
92         font->glyph_cache= NULL;
93         glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size);
94 }
95
96 FontBLF *blf_font_new(char *name, char *filename)
97 {
98         FontBLF *font;
99         FT_Error err;
100
101         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new");
102         err= FT_New_Face(global_ft_lib, filename, 0, &font->face);
103         if (err) {
104                 MEM_freeN(font);
105                 return(NULL);
106         }
107
108         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
109         if (err) {
110                 printf("Can't set the unicode character map!\n");
111                 FT_Done_Face(font->face);
112                 MEM_freeN(font);
113                 return(NULL);
114         }
115
116         font->name= BLI_strdup(name);
117         font->filename= BLI_strdup(filename);
118         blf_font_fill(font);
119         return(font);
120 }
121
122 FontBLF *blf_font_new_from_mem(char *name, unsigned char *mem, int mem_size)
123 {
124         FontBLF *font;
125         FT_Error err;
126
127         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new_from_mem");
128         err= FT_New_Memory_Face(global_ft_lib, mem, mem_size, 0, &font->face);
129         if (err) {
130                 MEM_freeN(font);
131                 return(NULL);
132         }
133
134         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
135         if (err) {
136                 printf("Can't set the unicode character map!\n");
137                 FT_Done_Face(font->face);
138                 MEM_freeN(font);
139                 return(NULL);
140         }
141
142         font->name= BLI_strdup(name);
143         font->filename= NULL;
144         blf_font_fill(font);
145         return(font);
146 }
147
148 void blf_font_size(FontBLF *font, int size, int dpi)
149 {
150         GlyphCacheBLF *gc;
151         FT_Error err;
152         
153         err= FT_Set_Char_Size(font->face, 0, (size * 64), dpi, dpi);
154         if (err) {
155                 /* FIXME: here we can go through the fixed size and choice a close one */
156                 printf("The current font don't support the size, %d and dpi, %d\n", size, dpi);
157                 return;
158         }
159
160         font->size= size;
161         font->dpi= dpi;
162
163         gc= blf_glyph_cache_find(font, size, dpi);
164         if (gc)
165                 font->glyph_cache= gc;
166         else {
167                 gc= blf_glyph_cache_new(font);
168                 if (gc)
169                         font->glyph_cache= gc;
170                 else
171                         font->glyph_cache= NULL;
172         }
173 }
174
175 void blf_font_draw(FontBLF *font, char *str)
176 {
177         unsigned int c;
178         GlyphBLF *g, *g_prev;
179         FT_Vector delta;
180         FT_UInt glyph_index;
181         int pen_x, pen_y;
182         int i, has_kerning;
183
184         i= 0;
185         pen_x= 0;
186         pen_y= 0;
187         has_kerning= FT_HAS_KERNING(font->face);
188         g_prev= NULL;
189
190         while (str[i]) {
191                 c= blf_utf8_next((unsigned char *)str, &i);
192                 if (c == 0)
193                         break;
194
195                 glyph_index= FT_Get_Char_Index(font->face, c);
196                 g= blf_glyph_search(font->glyph_cache, glyph_index);
197                 if (!g)
198                         g= blf_glyph_add(font, glyph_index, c);
199
200                 /* if we don't found a glyph, skip it. */
201                 if (!g)
202                         continue;
203
204                 if (has_kerning && g_prev) {
205                         delta.x= 0;
206                         delta.y= 0;
207
208                         FT_Get_Kerning(font->face, g_prev->index, glyph_index, FT_KERNING_UNFITTED, &delta);
209                         pen_x += delta.x >> 6;
210                 }
211
212                 blf_glyph_render(g, (float)pen_x, (float)pen_y);
213                 pen_x += g->advance;
214                 g_prev= g;
215         }
216 }
217
218 void blf_font_boundbox(FontBLF *font, char *str, rctf *box)
219 {
220         unsigned int c;
221         GlyphBLF *g, *g_prev;
222         FT_Vector delta;
223         FT_UInt glyph_index;
224         rctf gbox;
225         int pen_x, pen_y;
226         int i, has_kerning;
227
228         box->xmin= 32000.0f;
229         box->xmax= -32000.0f;
230         box->ymin= 32000.0f;
231         box->ymax= -32000.0f;
232
233         i= 0;
234         pen_x= 0;
235         pen_y= 0;
236         has_kerning= FT_HAS_KERNING(font->face);
237         g_prev= NULL;
238
239         while (str[i]) {
240                 c= blf_utf8_next((unsigned char *)str, &i);
241                 if (c == 0)
242                         break;
243
244                 glyph_index= FT_Get_Char_Index(font->face, c);
245                 g= blf_glyph_search(font->glyph_cache, glyph_index);
246                 if (!g)
247                         g= blf_glyph_add(font, glyph_index, c);
248
249                 /* if we don't found a glyph, skip it. */
250                 if (!g)
251                         continue;
252
253                 if (has_kerning && g_prev) {
254                         delta.x= 0;
255                         delta.y= 0;
256
257                         FT_Get_Kerning(font->face, g_prev->index, glyph_index, FT_KERNING_UNFITTED, &delta);
258                         pen_x += delta.x >> 6;
259                 }
260
261                 gbox.xmin= g->box.xmin + pen_x;
262                 gbox.xmax= g->box.xmax + pen_x;
263                 gbox.ymin= g->box.ymin + pen_y;
264                 gbox.ymax= g->box.ymax + pen_y;
265
266                 if (gbox.xmin < box->xmin)
267                         box->xmin= gbox.xmin;
268                 if (gbox.ymin < box->ymin)
269                         box->ymin= gbox.ymin;
270
271                 if (gbox.xmax > box->xmax)
272                         box->xmax= gbox.xmax;
273                 if (gbox.ymax > box->ymax)
274                         box->ymax= gbox.ymax;
275
276                 pen_x += g->advance;
277                 g_prev= g;
278         }
279
280         if (box->xmin > box->xmax) {
281                 box->xmin= 0.0f;
282                 box->ymin= 0.0f;
283                 box->xmax= 0.0f;
284                 box->ymax= 0.0f;
285         }
286 }
287
288 float blf_font_width(FontBLF *font, char *str)
289 {
290         rctf box;
291
292         blf_font_boundbox(font, str, &box);
293         return((box.xmax - box.xmin) * font->aspect);
294 }
295
296 float blf_font_height(FontBLF *font, char *str)
297 {
298         rctf box;
299
300         blf_font_boundbox(font, str, &box);
301         return((box.ymax - box.ymin) * font->aspect);
302 }
303
304 void blf_font_free(FontBLF *font)
305 {
306         GlyphCacheBLF *gc;
307
308         font->glyph_cache= NULL;
309         while (font->cache.first) {
310                 gc= font->cache.first;
311                 BLI_remlink(&font->cache, gc);
312                 blf_glyph_cache_free(gc);
313         }
314
315         FT_Done_Face(font->face);
316         if (font->filename)
317                 MEM_freeN(font->filename);
318         if (font->name)
319                 MEM_freeN(font->name);
320         MEM_freeN(font);
321 }
322
323 #endif /* WITH_FREETYPE2 */