235d8ecbf4644aa31a0cf8b121a609826432c1a6
[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] = {NULL};
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 (!blf_global_font_init())
464                 return;
465
466         BLF_size(global_font_default, global_font_points, global_font_dpi);
467         BLF_position(global_font_default, x, y, z);
468         BLF_draw(global_font_default, str, len);
469 }
470
471 /* same as above but call 'BLF_draw_ascii' */
472 void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len)
473 {
474         if (!blf_global_font_init())
475                 return;
476
477         BLF_size(global_font_default, global_font_points, global_font_dpi);
478         BLF_position(global_font_default, x, y, z);
479         BLF_draw_ascii(global_font_default, str, len); /* XXX, use real length */
480 }
481
482 void BLF_rotation_default(float angle)
483 {
484         FontBLF *font = blf_get(global_font_default);
485
486         if (font) {
487                 font->angle = angle;
488         }
489 }
490
491 static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param)
492 {
493         /*
494          * The pixmap alignment hack is handle
495          * in BLF_position (old ui_rasterpos_safe).
496          */
497
498         glEnable(GL_BLEND);
499         glEnable(GL_TEXTURE_2D);
500         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
501
502         /* Save the current matrix mode. */
503         glGetIntegerv(GL_MATRIX_MODE, mode);
504
505         glMatrixMode(GL_TEXTURE);
506         glPushMatrix();
507         glLoadIdentity();
508
509         glMatrixMode(GL_MODELVIEW);
510         glPushMatrix();
511
512         if (font->flags & BLF_MATRIX)
513                 glMultMatrixd((GLdouble *)&font->m);
514
515         glTranslatef(font->pos[0], font->pos[1], font->pos[2]);
516
517         if (font->flags & BLF_ASPECT)
518                 glScalef(font->aspect[0], font->aspect[1], font->aspect[2]);
519
520         if (font->flags & BLF_ROTATION)  /* radians -> degrees */
521                 glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f);
522
523         if (font->shadow || font->blur)
524                 glGetFloatv(GL_CURRENT_COLOR, font->orig_col);
525
526         /* always bind the texture for the first glyph */
527         font->tex_bind_state = -1;
528
529         /* Save the current parameter to restore it later. */
530         glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
531         if (*param != GL_MODULATE)
532                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
533 }
534
535 static void blf_draw__end(GLint mode, GLint param)
536 {
537         /* and restore the original value. */
538         if (param != GL_MODULATE)
539                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
540
541         glMatrixMode(GL_TEXTURE);
542         glPopMatrix();
543
544         glMatrixMode(GL_MODELVIEW);
545         glPopMatrix();
546
547         if (mode != GL_MODELVIEW)
548                 glMatrixMode(mode);
549
550         glDisable(GL_BLEND);
551         glDisable(GL_TEXTURE_2D);
552 }
553
554 void BLF_draw(int fontid, const char *str, size_t len)
555 {
556         FontBLF *font = blf_get(fontid);
557         GLint mode, param;
558
559         if (font && font->glyph_cache) {
560                 blf_draw__start(font, &mode, &param);
561                 blf_font_draw(font, str, len);
562                 blf_draw__end(mode, param);
563         }
564 }
565
566 void BLF_draw_ascii(int fontid, const char *str, size_t len)
567 {
568         FontBLF *font = blf_get(fontid);
569         GLint mode, param;
570
571         if (font && font->glyph_cache) {
572                 blf_draw__start(font, &mode, &param);
573                 blf_font_draw_ascii(font, str, len);
574                 blf_draw__end(mode, param);
575         }
576 }
577
578 int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
579 {
580         FontBLF *font = blf_get(fontid);
581         GLint mode, param;
582         int columns = 0;
583
584         if (font && font->glyph_cache) {
585                 blf_draw__start(font, &mode, &param);
586                 columns = blf_font_draw_mono(font, str, len, cwidth);
587                 blf_draw__end(mode, param);
588         }
589
590         return columns;
591 }
592
593 size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width)
594 {
595         FontBLF *font = blf_get(fontid);
596
597         if (font) {
598                 const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
599                 size_t ret;
600                 ret = blf_font_width_to_strlen(font, str, len, width / xa, r_width);
601                 if (r_width) {
602                         *r_width *= xa;
603                 }
604                 return ret;
605         }
606
607         if (r_width) {
608                 *r_width = 0.0f;
609         }
610         return 0;
611 }
612
613 size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width)
614 {
615         FontBLF *font = blf_get(fontid);
616
617         if (font) {
618                 const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
619                 size_t ret;
620                 ret = blf_font_width_to_rstrlen(font, str, len, width / xa, r_width);
621                 if (r_width) {
622                         *r_width *= xa;
623                 }
624                 return ret;
625         }
626
627         if (r_width) {
628                 *r_width = 0.0f;
629         }
630         return 0;
631 }
632
633 void BLF_boundbox(int fontid, const char *str, size_t len, rctf *box)
634 {
635         FontBLF *font = blf_get(fontid);
636
637         if (font) {
638                 blf_font_boundbox(font, str, len, box);
639         }
640 }
641
642 void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height)
643 {
644         FontBLF *font = blf_get(fontid);
645
646         if (font && font->glyph_cache) {
647                 blf_font_width_and_height(font, str, len, r_width, r_height);
648         }
649         else {
650                 *r_width = *r_height = 0.0f;
651         }
652 }
653
654 void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height)
655 {
656         if (!blf_global_font_init()) {
657                 *r_width = *r_height = 0.0f;
658                 return;
659         }
660
661         BLF_size(global_font_default, global_font_points, global_font_dpi);
662         BLF_width_and_height(global_font_default, str, len, r_width, r_height);
663 }
664
665 float BLF_width(int fontid, const char *str, size_t len)
666 {
667         FontBLF *font = blf_get(fontid);
668
669         if (font && font->glyph_cache) {
670                 return blf_font_width(font, str, len);
671         }
672
673         return 0.0f;
674 }
675
676 float BLF_fixed_width(int fontid)
677 {
678         FontBLF *font = blf_get(fontid);
679
680         if (font && font->glyph_cache) {
681                 return blf_font_fixed_width(font);
682         }
683
684         return 0.0f;
685 }
686
687 float BLF_width_default(const char *str, size_t len)
688 {
689         if (!blf_global_font_init())
690                 return 0.0f;
691
692         BLF_size(global_font_default, global_font_points, global_font_dpi);
693         return BLF_width(global_font_default, str, len);
694 }
695
696 float BLF_height(int fontid, const char *str, size_t len)
697 {
698         FontBLF *font = blf_get(fontid);
699
700         if (font && font->glyph_cache) {
701                 return blf_font_height(font, str, len);
702         }
703
704         return 0.0f;
705 }
706
707 float BLF_height_max(int fontid)
708 {
709         FontBLF *font = blf_get(fontid);
710
711         if (font && font->glyph_cache) {
712                 return font->glyph_cache->max_glyph_height;
713         }
714
715         return 0.0f;
716 }
717
718 float BLF_width_max(int fontid)
719 {
720         FontBLF *font = blf_get(fontid);
721
722         if (font && font->glyph_cache) {
723                 return font->glyph_cache->max_glyph_width;
724         }
725
726         return 0.0f;
727 }
728
729 float BLF_descender(int fontid)
730 {
731         FontBLF *font = blf_get(fontid);
732
733         if (font && font->glyph_cache) {
734                 return font->glyph_cache->descender;
735         }
736
737         return 0.0f;
738 }
739
740 float BLF_ascender(int fontid)
741 {
742         FontBLF *font = blf_get(fontid);
743
744         if (font && font->glyph_cache) {
745                 return font->glyph_cache->ascender;
746         }
747
748         return 0.0f;
749 }
750
751 float BLF_height_default(const char *str, size_t len)
752 {
753         if (!blf_global_font_init())
754                 return 0.0f;
755
756         BLF_size(global_font_default, global_font_points, global_font_dpi);
757
758         return BLF_height(global_font_default, str, len);
759 }
760
761 void BLF_rotation(int fontid, float angle)
762 {
763         FontBLF *font = blf_get(fontid);
764
765         if (font) {
766                 font->angle = angle;
767         }
768 }
769
770 void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax)
771 {
772         FontBLF *font = blf_get(fontid);
773
774         if (font) {
775                 font->clip_rec.xmin = xmin;
776                 font->clip_rec.ymin = ymin;
777                 font->clip_rec.xmax = xmax;
778                 font->clip_rec.ymax = ymax;
779         }
780 }
781
782 void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax)
783 {
784         FontBLF *font = blf_get(global_font_default);
785
786         if (font) {
787                 font->clip_rec.xmin = xmin;
788                 font->clip_rec.ymin = ymin;
789                 font->clip_rec.xmax = xmax;
790                 font->clip_rec.ymax = ymax;
791         }
792 }
793
794 void BLF_shadow(int fontid, int level, float r, float g, float b, float a)
795 {
796         FontBLF *font = blf_get(fontid);
797
798         if (font) {
799                 font->shadow = level;
800                 font->shadow_col[0] = r;
801                 font->shadow_col[1] = g;
802                 font->shadow_col[2] = b;
803                 font->shadow_col[3] = a;
804         }
805 }
806
807 void BLF_shadow_offset(int fontid, int x, int y)
808 {
809         FontBLF *font = blf_get(fontid);
810
811         if (font) {
812                 font->shadow_x = x;
813                 font->shadow_y = y;
814         }
815 }
816
817 void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, int nch, struct ColorManagedDisplay *display)
818 {
819         FontBLF *font = blf_get(fontid);
820
821         if (font) {
822                 font->buf_info.fbuf = fbuf;
823                 font->buf_info.cbuf = cbuf;
824                 font->buf_info.w = w;
825                 font->buf_info.h = h;
826                 font->buf_info.ch = nch;
827                 font->buf_info.display = display;
828         }
829 }
830
831 void BLF_buffer_col(int fontid, float r, float g, float b, float a)
832 {
833         FontBLF *font = blf_get(fontid);
834
835         if (font) {
836                 font->buf_info.col[0] = r;
837                 font->buf_info.col[1] = g;
838                 font->buf_info.col[2] = b;
839                 font->buf_info.col[3] = a;
840         }
841 }
842
843 void BLF_draw_buffer(int fontid, const char *str)
844 {
845         FontBLF *font = blf_get(fontid);
846
847         if (font && font->glyph_cache && (font->buf_info.fbuf || font->buf_info.cbuf)) {
848                 blf_font_buffer(font, str);
849         }
850 }
851
852 #ifdef DEBUG
853 void BLF_state_print(int fontid)
854 {
855         FontBLF *font = blf_get(fontid);
856         if (font) {
857                 printf("fontid %d %p\n", fontid, (void *)font);
858                 printf("  name:    '%s'\n", font->name);
859                 printf("  size:     %u\n", font->size);
860                 printf("  dpi:      %u\n", font->dpi);
861                 printf("  pos:      %.6f %.6f %.6f\n", UNPACK3(font->pos));
862                 printf("  aspect:   (%d) %.6f %.6f %.6f\n", (font->flags & BLF_ROTATION) != 0, UNPACK3(font->aspect));
863                 printf("  angle:    (%d) %.6f\n", (font->flags & BLF_ASPECT) != 0, font->angle);
864                 printf("  flag:     %d\n", font->flags);
865         }
866         else {
867                 printf("fontid %d (NULL)\n", fontid);
868         }
869         fflush(stdout);
870 }
871 #endif