54f94ad7b87bf6d01eb2f83e24f9471b41c61fae
[blender.git] / source / blender / blenfont / intern / blf.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/blenfont/intern/blf.c
28  *  \ingroup blf
29  *
30  * Main BlenFont (BLF) API, public functions for font handling.
31  *
32  * Wraps OpenGL and FreeType.
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <math.h>
39
40 #include <ft2build.h>
41
42 #include FT_FREETYPE_H
43 #include FT_GLYPH_H
44
45 #include "MEM_guardedalloc.h"
46
47 #include "DNA_listBase.h"
48 #include "DNA_vec_types.h"
49
50 #include "BLI_math.h"
51 #include "BLI_threads.h"
52
53 #include "BIF_gl.h"
54 #include "BLF_api.h"
55
56 #include "blf_internal_types.h"
57 #include "blf_internal.h"
58
59 /* Max number of font in memory.
60  * Take care that now every font have a glyph cache per size/dpi,
61  * so we don't need load the same font with different size, just
62  * load one and call BLF_size.
63  */
64 #define BLF_MAX_FONT 16
65
66 /* Font array. */
67 static FontBLF *global_font[BLF_MAX_FONT] = {0};
68
69 /* Default size and dpi, for BLF_draw_default. */
70 static int global_font_default = -1;
71 static int global_font_points = 11;
72 static int global_font_dpi = 72;
73
74 /* XXX, should these be made into global_font_'s too? */
75 int blf_mono_font = -1;
76 int blf_mono_font_render = -1;
77
78 static FontBLF *blf_get(int fontid)
79 {
80         if (fontid >= 0 && fontid < BLF_MAX_FONT)
81                 return global_font[fontid];
82         return NULL;
83 }
84
85 int BLF_init(int points, int dpi)
86 {
87         int i;
88
89         for (i = 0; i < BLF_MAX_FONT; i++)
90                 global_font[i] = NULL;
91
92         global_font_points = points;
93         global_font_dpi = dpi;
94         return blf_font_init();
95 }
96
97 void BLF_default_dpi(int dpi)
98 {
99         global_font_dpi = dpi;
100 }
101
102 void BLF_exit(void)
103 {
104         FontBLF *font;
105         int i;
106
107         for (i = 0; i < BLF_MAX_FONT; i++) {
108                 font = global_font[i];
109                 if (font) {
110                         blf_font_free(font);
111                         global_font[i] = NULL;
112                 }
113         }
114
115         blf_font_exit();
116 }
117
118 void BLF_cache_clear(void)
119 {
120         FontBLF *font;
121         int i;
122
123         for (i = 0; i < BLF_MAX_FONT; i++) {
124                 font = global_font[i];
125                 if (font)
126                         blf_glyph_cache_clear(font);
127         }
128 }
129
130 static int blf_search(const char *name)
131 {
132         FontBLF *font;
133         int i;
134
135         for (i = 0; i < BLF_MAX_FONT; i++) {
136                 font = global_font[i];
137                 if (font && (!strcmp(font->name, name)))
138                         return i;
139         }
140
141         return -1;
142 }
143
144 static int blf_search_available(void)
145 {
146         int i;
147
148         for (i = 0; i < BLF_MAX_FONT; i++)
149                 if (!global_font[i])
150                         return i;
151         
152         return -1;
153 }
154
155 static int blf_global_font_init(void)
156 {
157         if (global_font_default == -1) {
158                 global_font_default = blf_search("default");
159         }
160
161         if (global_font_default == -1) {
162                 printf("Warning: Can't find default font!\n");
163                 return 0;
164         }
165         else {
166                 return 1;
167         }
168 }
169
170 int BLF_load(const char *name)
171 {
172         FontBLF *font;
173         char *filename;
174         int i;
175
176         if (!name)
177                 return -1;
178
179         /* check if we already load this font. */
180         i = blf_search(name);
181         if (i >= 0) {
182                 /*font = global_font[i];*/ /*UNUSED*/
183                 return i;
184         }
185
186         i = blf_search_available();
187         if (i == -1) {
188                 printf("Too many fonts!!!\n");
189                 return -1;
190         }
191
192         filename = blf_dir_search(name);
193         if (!filename) {
194                 printf("Can't find font: %s\n", name);
195                 return -1;
196         }
197
198         font = blf_font_new(name, filename);
199         MEM_freeN(filename);
200
201         if (!font) {
202                 printf("Can't load font: %s\n", name);
203                 return -1;
204         }
205
206         global_font[i] = font;
207         return i;
208 }
209
210 int BLF_load_unique(const char *name)
211 {
212         FontBLF *font;
213         char *filename;
214         int i;
215
216         if (!name)
217                 return -1;
218
219         /* Don't search in the cache!! make a new
220          * object font, this is for keep fonts threads safe.
221          */
222         i = blf_search_available();
223         if (i == -1) {
224                 printf("Too many fonts!!!\n");
225                 return -1;
226         }
227
228         filename = blf_dir_search(name);
229         if (!filename) {
230                 printf("Can't find font: %s\n", name);
231                 return -1;
232         }
233
234         font = blf_font_new(name, filename);
235         MEM_freeN(filename);
236
237         if (!font) {
238                 printf("Can't load font: %s\n", name);
239                 return -1;
240         }
241
242         global_font[i] = font;
243         return i;
244 }
245
246 void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size)
247 {
248         FontBLF *font = blf_get(fontid);
249
250         if (font) {
251                 blf_font_attach_from_mem(font, mem, mem_size);
252         }
253 }
254
255 int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size)
256 {
257         FontBLF *font;
258         int i;
259
260         if (!name)
261                 return -1;
262
263         i = blf_search(name);
264         if (i >= 0) {
265                 /*font = global_font[i];*/ /*UNUSED*/
266                 return i;
267         }
268
269         i = blf_search_available();
270         if (i == -1) {
271                 printf("Too many fonts!!!\n");
272                 return -1;
273         }
274
275         if (!mem || !mem_size) {
276                 printf("Can't load font: %s from memory!!\n", name);
277                 return -1;
278         }
279
280         font = blf_font_new_from_mem(name, mem, mem_size);
281         if (!font) {
282                 printf("Can't load font: %s from memory!!\n", name);
283                 return -1;
284         }
285
286         global_font[i] = font;
287         return i;
288 }
289
290 int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size)
291 {
292         FontBLF *font;
293         int i;
294
295         if (!name)
296                 return -1;
297
298         /*
299          * Don't search in the cache, make a new object font!
300          * this is to keep the font thread safe.
301          */
302         i = blf_search_available();
303         if (i == -1) {
304                 printf("Too many fonts!!!\n");
305                 return -1;
306         }
307
308         if (!mem || !mem_size) {
309                 printf("Can't load font: %s from memory!!\n", name);
310                 return -1;
311         }
312
313         font = blf_font_new_from_mem(name, mem, mem_size);
314         if (!font) {
315                 printf("Can't load font: %s from memory!!\n", name);
316                 return -1;
317         }
318
319         global_font[i] = font;
320         return i;
321 }
322
323 void BLF_unload(const char *name)
324 {
325         FontBLF *font;
326         int i;
327
328         for (i = 0; i < BLF_MAX_FONT; i++) {
329                 font = global_font[i];
330
331                 if (font && (!strcmp(font->name, name))) {
332                         blf_font_free(font);
333                         global_font[i] = NULL;
334                 }
335         }
336 }
337
338 void BLF_enable(int fontid, int option)
339 {
340         FontBLF *font = blf_get(fontid);
341
342         if (font) {
343                 font->flags |= option;
344         }
345 }
346
347 void BLF_disable(int fontid, int option)
348 {
349         FontBLF *font = blf_get(fontid);
350
351         if (font) {
352                 font->flags &= ~option;
353         }
354 }
355
356 void BLF_enable_default(int option)
357 {
358         FontBLF *font = blf_get(global_font_default);
359
360         if (font) {
361                 font->flags |= option;
362         }
363 }
364
365 void BLF_disable_default(int option)
366 {
367         FontBLF *font = blf_get(global_font_default);
368
369         if (font) {
370                 font->flags &= ~option;
371         }
372 }
373
374 void BLF_aspect(int fontid, float x, float y, float z)
375 {
376         FontBLF *font = blf_get(fontid);
377
378         if (font) {
379                 font->aspect[0] = x;
380                 font->aspect[1] = y;
381                 font->aspect[2] = z;
382         }
383 }
384
385 void BLF_matrix(int fontid, const double m[16])
386 {
387         FontBLF *font = blf_get(fontid);
388
389         if (font) {
390                 memcpy(font->m, m, sizeof(font->m));
391         }
392 }
393
394 void BLF_position(int fontid, float x, float y, float z)
395 {
396         FontBLF *font = blf_get(fontid);
397
398         if (font) {
399                 float xa, ya, za;
400                 float remainder;
401
402                 if (font->flags & BLF_ASPECT) {
403                         xa = font->aspect[0];
404                         ya = font->aspect[1];
405                         za = font->aspect[2];
406                 }
407                 else {
408                         xa = 1.0f;
409                         ya = 1.0f;
410                         za = 1.0f;
411                 }
412
413                 remainder = x - floorf(x);
414                 if (remainder > 0.4f && remainder < 0.6f) {
415                         if (remainder < 0.5f)
416                                 x -= 0.1f * xa;
417                         else
418                                 x += 0.1f * xa;
419                 }
420
421                 remainder = y - floorf(y);
422                 if (remainder > 0.4f && remainder < 0.6f) {
423                         if (remainder < 0.5f)
424                                 y -= 0.1f * ya;
425                         else
426                                 y += 0.1f * ya;
427                 }
428
429                 remainder = z - floorf(z);
430                 if (remainder > 0.4f && remainder < 0.6f) {
431                         if (remainder < 0.5f)
432                                 z -= 0.1f * za;
433                         else
434                                 z += 0.1f * za;
435                 }
436
437                 font->pos[0] = x;
438                 font->pos[1] = y;
439                 font->pos[2] = z;
440         }
441 }
442
443 void BLF_size(int fontid, int size, int dpi)
444 {
445         FontBLF *font = blf_get(fontid);
446
447         if (font) {
448                 blf_font_size(font, size, dpi);
449         }
450 }
451
452 void BLF_blur(int fontid, int size)
453 {
454         FontBLF *font = blf_get(fontid);
455
456         if (font) {
457                 font->blur = size;
458         }
459 }
460
461 void BLF_draw_default(float x, float y, float z, const char *str, size_t len)
462 {
463         if (!str)
464                 return;
465
466         if (!blf_global_font_init())
467                 return;
468
469         BLF_size(global_font_default, global_font_points, global_font_dpi);
470         BLF_position(global_font_default, x, y, z);
471         BLF_draw(global_font_default, str, len);
472 }
473
474 /* same as above but call 'BLF_draw_ascii' */
475 void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len)
476 {
477         if (!str)
478                 return;
479
480         if (!blf_global_font_init())
481                 return;
482
483         BLF_size(global_font_default, global_font_points, global_font_dpi);
484         BLF_position(global_font_default, x, y, z);
485         BLF_draw_ascii(global_font_default, str, len); /* XXX, use real length */
486 }
487
488 void BLF_rotation_default(float angle)
489 {
490         FontBLF *font = blf_get(global_font_default);
491
492         if (font) {
493                 font->angle = angle;
494         }
495 }
496
497 static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param)
498 {
499         /*
500          * The pixmap alignment hack is handle
501          * in BLF_position (old ui_rasterpos_safe).
502          */
503
504         glEnable(GL_BLEND);
505         glEnable(GL_TEXTURE_2D);
506         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
507
508         /* Save the current matrix mode. */
509         glGetIntegerv(GL_MATRIX_MODE, mode);
510
511         glMatrixMode(GL_TEXTURE);
512         glPushMatrix();
513         glLoadIdentity();
514
515         glMatrixMode(GL_MODELVIEW);
516         glPushMatrix();
517
518         if (font->flags & BLF_MATRIX)
519                 glMultMatrixd((GLdouble *)&font->m);
520
521         glTranslatef(font->pos[0], font->pos[1], font->pos[2]);
522
523         if (font->flags & BLF_ASPECT)
524                 glScalef(font->aspect[0], font->aspect[1], font->aspect[2]);
525
526         if (font->flags & BLF_ROTATION)  /* radians -> degrees */
527                 glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f);
528
529         if (font->shadow || font->blur)
530                 glGetFloatv(GL_CURRENT_COLOR, font->orig_col);
531
532         /* always bind the texture for the first glyph */
533         font->tex_bind_state = -1;
534
535         /* Save the current parameter to restore it later. */
536         glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
537         if (*param != GL_MODULATE)
538                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
539 }
540
541 static void blf_draw__end(GLint mode, GLint param)
542 {
543         /* and restore the original value. */
544         if (param != GL_MODULATE)
545                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
546
547         glMatrixMode(GL_TEXTURE);
548         glPopMatrix();
549
550         glMatrixMode(GL_MODELVIEW);
551         glPopMatrix();
552
553         if (mode != GL_MODELVIEW)
554                 glMatrixMode(mode);
555
556         glDisable(GL_BLEND);
557         glDisable(GL_TEXTURE_2D);
558 }
559
560 void BLF_draw(int fontid, const char *str, size_t len)
561 {
562         FontBLF *font = blf_get(fontid);
563         GLint mode, param;
564
565         if (font && font->glyph_cache) {
566                 blf_draw__start(font, &mode, &param);
567                 blf_font_draw(font, str, len);
568                 blf_draw__end(mode, param);
569         }
570 }
571
572 void BLF_draw_ascii(int fontid, const char *str, size_t len)
573 {
574         FontBLF *font = blf_get(fontid);
575         GLint mode, param;
576
577         if (font && font->glyph_cache) {
578                 blf_draw__start(font, &mode, &param);
579                 blf_font_draw_ascii(font, str, len);
580                 blf_draw__end(mode, param);
581         }
582 }
583
584 int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
585 {
586         FontBLF *font = blf_get(fontid);
587         GLint mode, param;
588         int columns = 0;
589
590         if (font && font->glyph_cache) {
591                 blf_draw__start(font, &mode, &param);
592                 columns = blf_font_draw_mono(font, str, len, cwidth);
593                 blf_draw__end(mode, param);
594         }
595
596         return columns;
597 }
598
599 size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width)
600 {
601         FontBLF *font = blf_get(fontid);
602
603         if (font) {
604                 const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
605                 size_t ret;
606                 ret = blf_font_width_to_strlen(font, str, len, width / xa, r_width);
607                 if (r_width) {
608                         *r_width *= xa;
609                 }
610                 return ret;
611         }
612
613         if (r_width) {
614                 *r_width = 0.0f;
615         }
616         return 0;
617 }
618
619 size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width)
620 {
621         FontBLF *font = blf_get(fontid);
622
623         if (font) {
624                 const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
625                 size_t ret;
626                 ret = blf_font_width_to_rstrlen(font, str, len, width / xa, r_width);
627                 if (r_width) {
628                         *r_width *= xa;
629                 }
630                 return ret;
631         }
632
633         if (r_width) {
634                 *r_width = 0.0f;
635         }
636         return 0;
637 }
638
639 void BLF_boundbox(int fontid, const char *str, size_t len, rctf *box)
640 {
641         FontBLF *font = blf_get(fontid);
642
643         if (font) {
644                 blf_font_boundbox(font, str, len, box);
645         }
646 }
647
648 void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height)
649 {
650         FontBLF *font = blf_get(fontid);
651
652         if (font && font->glyph_cache) {
653                 blf_font_width_and_height(font, str, len, r_width, r_height);
654         }
655         else {
656                 *r_width = *r_height = 0.0f;
657         }
658 }
659
660 void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height)
661 {
662         if (!blf_global_font_init()) {
663                 *r_width = *r_height = 0.0f;
664                 return;
665         }
666
667         BLF_size(global_font_default, global_font_points, global_font_dpi);
668         BLF_width_and_height(global_font_default, str, len, r_width, r_height);
669 }
670
671 float BLF_width(int fontid, const char *str, size_t len)
672 {
673         FontBLF *font = blf_get(fontid);
674
675         if (font && font->glyph_cache) {
676                 return blf_font_width(font, str, len);
677         }
678
679         return 0.0f;
680 }
681
682 float BLF_fixed_width(int fontid)
683 {
684         FontBLF *font = blf_get(fontid);
685
686         if (font && font->glyph_cache) {
687                 return blf_font_fixed_width(font);
688         }
689
690         return 0.0f;
691 }
692
693 float BLF_width_default(const char *str, size_t len)
694 {
695         if (!blf_global_font_init())
696                 return 0.0f;
697
698         BLF_size(global_font_default, global_font_points, global_font_dpi);
699         return BLF_width(global_font_default, str, len);
700 }
701
702 float BLF_height(int fontid, const char *str, size_t len)
703 {
704         FontBLF *font = blf_get(fontid);
705
706         if (font && font->glyph_cache) {
707                 return blf_font_height(font, str, len);
708         }
709
710         return 0.0f;
711 }
712
713 float BLF_height_max(int fontid)
714 {
715         FontBLF *font = blf_get(fontid);
716
717         if (font && font->glyph_cache) {
718                 return font->glyph_cache->max_glyph_height;
719         }
720
721         return 0.0f;
722 }
723
724 float BLF_width_max(int fontid)
725 {
726         FontBLF *font = blf_get(fontid);
727
728         if (font && font->glyph_cache) {
729                 return font->glyph_cache->max_glyph_width;
730         }
731
732         return 0.0f;
733 }
734
735 float BLF_descender(int fontid)
736 {
737         FontBLF *font = blf_get(fontid);
738
739         if (font && font->glyph_cache) {
740                 return font->glyph_cache->descender;
741         }
742
743         return 0.0f;
744 }
745
746 float BLF_ascender(int fontid)
747 {
748         FontBLF *font = blf_get(fontid);
749
750         if (font && font->glyph_cache) {
751                 return font->glyph_cache->ascender;
752         }
753
754         return 0.0f;
755 }
756
757 float BLF_height_default(const char *str, size_t len)
758 {
759         if (!blf_global_font_init())
760                 return 0.0f;
761
762         BLF_size(global_font_default, global_font_points, global_font_dpi);
763
764         return BLF_height(global_font_default, str, len);
765 }
766
767 void BLF_rotation(int fontid, float angle)
768 {
769         FontBLF *font = blf_get(fontid);
770
771         if (font) {
772                 font->angle = angle;
773         }
774 }
775
776 void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax)
777 {
778         FontBLF *font = blf_get(fontid);
779
780         if (font) {
781                 font->clip_rec.xmin = xmin;
782                 font->clip_rec.ymin = ymin;
783                 font->clip_rec.xmax = xmax;
784                 font->clip_rec.ymax = ymax;
785         }
786 }
787
788 void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax)
789 {
790         FontBLF *font = blf_get(global_font_default);
791
792         if (font) {
793                 font->clip_rec.xmin = xmin;
794                 font->clip_rec.ymin = ymin;
795                 font->clip_rec.xmax = xmax;
796                 font->clip_rec.ymax = ymax;
797         }
798 }
799
800 void BLF_shadow(int fontid, int level, float r, float g, float b, float a)
801 {
802         FontBLF *font = blf_get(fontid);
803
804         if (font) {
805                 font->shadow = level;
806                 font->shadow_col[0] = r;
807                 font->shadow_col[1] = g;
808                 font->shadow_col[2] = b;
809                 font->shadow_col[3] = a;
810         }
811 }
812
813 void BLF_shadow_offset(int fontid, int x, int y)
814 {
815         FontBLF *font = blf_get(fontid);
816
817         if (font) {
818                 font->shadow_x = x;
819                 font->shadow_y = y;
820         }
821 }
822
823 void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, int nch, struct ColorManagedDisplay *display)
824 {
825         FontBLF *font = blf_get(fontid);
826
827         if (font) {
828                 font->buf_info.fbuf = fbuf;
829                 font->buf_info.cbuf = cbuf;
830                 font->buf_info.w = w;
831                 font->buf_info.h = h;
832                 font->buf_info.ch = nch;
833                 font->buf_info.display = display;
834         }
835 }
836
837 void BLF_buffer_col(int fontid, float r, float g, float b, float a)
838 {
839         FontBLF *font = blf_get(fontid);
840
841         if (font) {
842                 font->buf_info.col[0] = r;
843                 font->buf_info.col[1] = g;
844                 font->buf_info.col[2] = b;
845                 font->buf_info.col[3] = a;
846         }
847 }
848
849 void BLF_draw_buffer(int fontid, const char *str)
850 {
851         FontBLF *font = blf_get(fontid);
852
853         if (font && font->glyph_cache && (font->buf_info.fbuf || font->buf_info.cbuf)) {
854                 blf_font_buffer(font, str);
855         }
856 }
857
858 #ifdef DEBUG
859 void BLF_state_print(int fontid)
860 {
861         FontBLF *font = blf_get(fontid);
862         if (font) {
863                 printf("fontid %d %p\n", fontid, (void *)font);
864                 printf("  name:    '%s'\n", font->name);
865                 printf("  size:     %u\n", font->size);
866                 printf("  dpi:      %u\n", font->dpi);
867                 printf("  pos:      %.6f %.6f %.6f\n", UNPACK3(font->pos));
868                 printf("  aspect:   (%d) %.6f %.6f %.6f\n", (font->flags & BLF_ROTATION) != 0, UNPACK3(font->aspect));
869                 printf("  angle:    (%d) %.6f\n", (font->flags & BLF_ASPECT) != 0, font->angle);
870                 printf("  flag:     %d\n", font->flags);
871         }
872         else {
873                 printf("fontid %d (NULL)\n", fontid);
874         }
875         fflush(stdout);
876 }
877 #endif