Fix for #1700 and #1941
[blender.git] / source / blender / blenkernel / intern / font.c
1
2 /*  font.c     
3  *  
4  * 
5  * $Id$
6  *
7  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version. The Blender
13  * Foundation also sells licenses for use in proprietary software under
14  * the Blender License.  See http://www.blender.org/BL/ for information
15  * about this.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
27  * All rights reserved.
28  *
29  * The Original Code is: all of this file.
30  *
31  * Contributor(s): none yet.
32  *
33  * ***** END GPL/BL DUAL LICENSE BLOCK *****
34  */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <math.h>
39 #include <stdlib.h>
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 #ifdef WIN32
46 #include "BLI_winstuff.h"
47 #endif
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_arithb.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_vfontdata.h"
53
54 #include "DNA_packedFile_types.h"
55 #include "DNA_curve_types.h"
56 #include "DNA_object_types.h"
57 #include "DNA_view3d_types.h"
58 #include "DNA_vfont_types.h"
59 #include "DNA_scene_types.h"
60
61 #include "BKE_utildefines.h"
62 #include "BKE_bad_level_calls.h"
63
64 #include "BKE_packedFile.h"
65
66 #include "BKE_library.h"
67 #include "BKE_font.h"
68 #include "BKE_global.h"
69 #include "BKE_main.h"
70 #include "BKE_screen.h"
71 #include "BKE_anim.h"
72 #include "BKE_curve.h"
73 #include "BKE_displist.h"
74
75
76 struct chartrans {
77         float xof, yof;
78         float rot;
79         short linenr,charnr;
80 };
81
82 void free_vfont(struct VFont *vf)
83 {
84         int i;
85
86         if (vf == 0) return;
87
88         if (vf->data) {
89                 for (i = 0; i < MAX_VF_CHARS; i++){
90                         while (vf->data->nurbsbase[i].first) {
91                                 Nurb *nu = vf->data->nurbsbase[i].first;
92                                 if (nu->bezt) MEM_freeN(nu->bezt);
93                                 BLI_freelinkN(&vf->data->nurbsbase[i], nu);
94                         }
95                 }
96
97                 MEM_freeN(vf->data);
98                 vf->data = NULL;
99         }
100         
101         if (vf->packedfile) {
102                 freePackedFile(vf->packedfile);
103                 vf->packedfile = NULL;
104         }
105 }
106
107 static void *builtin_font_data= NULL;
108 static int builtin_font_size= 0;
109
110 void BKE_font_register_builtin(void *mem, int size)
111 {
112         builtin_font_data= mem;
113         builtin_font_size= size;
114 }
115
116 static PackedFile *get_builtin_packedfile(void)
117 {
118         if (!builtin_font_data) {
119                 printf("Internal error, builtin font not loaded\n");
120
121                 return NULL;
122         } else {
123                 void *mem= MEM_mallocN(builtin_font_size, "vfd_builtin");
124
125                 memcpy(mem, builtin_font_data, builtin_font_size);
126         
127                 return newPackedFileMemory(mem, builtin_font_size);
128         }
129 }
130
131 static VFontData *vfont_get_data(VFont *vfont)
132 {
133         if (!vfont->data) {
134                 PackedFile *pf;
135                 
136                 if (BLI_streq(vfont->name, "<builtin>")) {
137                         pf= get_builtin_packedfile();
138                 } else {
139                         if (vfont->packedfile) {
140                                 pf= vfont->packedfile;
141                         } else {
142                                 pf= newPackedFile(vfont->name);
143                         }
144                         if(!pf) {
145                                 printf("Font file doesn't exist: %s\n", vfont->name);
146
147                                 strcpy(vfont->name, "<builtin>");
148                                 pf= get_builtin_packedfile();
149                         }
150                 }
151                 
152                 if (pf) {
153 #ifdef WITH_FREETYPE2
154                         vfont->data= BLI_vfontdata_from_freetypefont(pf);
155 #else
156                         vfont->data= BLI_vfontdata_from_psfont(pf);
157 #endif                  
158                         if (pf != vfont->packedfile) {
159                                 freePackedFile(pf);
160                         }
161                 }
162         }
163         
164         return vfont->data;     
165 }
166
167 VFont *load_vfont(char *name)
168 {
169         char filename[FILE_MAXFILE];
170         VFont *vfont= NULL;
171         PackedFile *pf;
172         int is_builtin;
173         
174         if (BLI_streq(name, "<builtin>")) {
175                 strcpy(filename, name);
176                 
177                 pf= get_builtin_packedfile();
178                 is_builtin= 1;
179         } else {
180                 char dir[FILE_MAXDIR];
181                 
182                 strcpy(dir, name);
183                 BLI_splitdirstring(dir, filename);
184
185                 pf= newPackedFile(name);
186                 is_builtin= 0;
187         }
188
189         if (pf) {
190                 VFontData *vfd;
191                 
192                 waitcursor(1);
193
194 #ifdef WITH_FREETYPE2
195                 vfd= BLI_vfontdata_from_freetypefont(pf);
196 #else
197                 vfd= BLI_vfontdata_from_psfont(pf);
198 #endif                  
199                 
200                 if (vfd) {
201                         vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
202                         vfont->data = vfd;
203                         
204                         BLI_strncpy(vfont->name, name, sizeof(vfont->name));
205
206                         // if autopack is on store the packedfile in de font structure
207                         if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
208                                 vfont->packedfile = pf;
209                         }
210                 }
211                 if (!vfont || vfont->packedfile != pf) {
212                         freePackedFile(pf);
213                 }
214         
215                 waitcursor(0);
216         }
217         
218         return vfont;
219 }
220
221 static void buildchar(Curve *cu, unsigned char ascii, float ofsx, float ofsy, float rot)
222 {
223         BezTriple *bezt1, *bezt2;
224         Nurb *nu1, *nu2;
225         float *fp, fsize, shear, x, si, co;
226         VFontData *vfd;
227         int i;
228
229         vfd= vfont_get_data(cu->vfont); 
230         if (!vfd) return;
231         
232         /* make a copy at distance ofsx,ofsy with shear*/
233         fsize= cu->fsize;
234         shear= cu->shear;
235         si= (float)sin(rot);
236         co= (float)cos(rot);
237
238         nu1 = vfd->nurbsbase[ascii].first;
239         while(nu1)
240         {
241                 bezt1 = nu1->bezt;
242                 if (bezt1){
243                         nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb");
244                         if (nu2 == 0) break;
245                         memcpy(nu2, nu1, sizeof(struct Nurb));
246                         nu2->resolu= cu->resolu;
247                         nu2->bp = 0;
248                         nu2->knotsu = nu2->knotsv = 0;
249                         nu2->flag= CU_SMOOTH;
250                         /* nu2->trim.first = 0; */
251                         /* nu2->trim.last = 0; */
252                         i = nu2->pntsu;
253
254                         bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2"); 
255                         if (bezt2 == 0){
256                                 MEM_freeN(nu2);
257                                 break;
258                         }
259                         memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
260                         nu2->bezt = bezt2;
261                         
262                         if (shear != 0.0) {
263                                 bezt2 = nu2->bezt;
264                                 
265                                 for (i= nu2->pntsu; i > 0; i--) {
266                                         bezt2->vec[0][0] += shear * bezt2->vec[0][1];
267                                         bezt2->vec[1][0] += shear * bezt2->vec[1][1];
268                                         bezt2->vec[2][0] += shear * bezt2->vec[2][1];
269                                         bezt2++;
270                                 }
271                         }
272                         if(rot!=0.0) {
273                                 bezt2= nu2->bezt;
274                                 for (i=nu2->pntsu; i > 0; i--) {
275                                         fp= bezt2->vec[0];
276                                         
277                                         x= fp[0];
278                                         fp[0]= co*x + si*fp[1];
279                                         fp[1]= -si*x + co*fp[1];
280                                         x= fp[3];
281                                         fp[3]= co*x + si*fp[4];
282                                         fp[4]= -si*x + co*fp[4];
283                                         x= fp[6];
284                                         fp[6]= co*x + si*fp[7];
285                                         fp[7]= -si*x + co*fp[7];
286
287                                         bezt2++;
288                                 }
289                         }
290                         bezt2 = nu2->bezt;
291                         
292                         for (i= nu2->pntsu; i > 0; i--) {
293                                 fp= bezt2->vec[0];
294
295                                 fp[0]= (fp[0]+ofsx)*fsize;
296                                 fp[1]= (fp[1]+ofsy)*fsize;
297                                 fp[3]= (fp[3]+ofsx)*fsize;
298                                 fp[4]= (fp[4]+ofsy)*fsize;
299                                 fp[6]= (fp[6]+ofsx)*fsize;
300                                 fp[7]= (fp[7]+ofsy)*fsize;
301                                 bezt2++;
302                         }
303                         
304                         BLI_addtail(&(cu->nurb), nu2);
305                 }
306                 nu1 = nu1->next;
307         }
308 }
309
310
311 struct chartrans *text_to_curve(Object *ob, int mode) 
312 {
313         VFont *vfont;
314         VFontData *vfd;
315         Curve *cu, *cucu;
316         struct chartrans *chartransdata, *ct;
317         float distfac, tabfac, ctime, dtime, tvec[4], vec[4], rotvec[3], minx, maxx, miny, maxy;
318         float cmat[3][3], timeofs, si, co, sizefac;
319         float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2;
320         int i, slen, oldflag;
321         short cnr=0, lnr=0;
322         char ascii, *mem;
323
324         /* renark: do calculations including the trailing '\0' of a string
325            because the cursor can be at that location */
326
327         if(ob->type!=OB_FONT) return 0;
328
329         cu= ob->data;
330
331         vfont= cu->vfont;
332         if (vfont==0) return 0;
333         if (cu->str==0) return 0;
334
335         vfd= vfont_get_data(vfont);
336         if (!vfd) return 0;
337         
338         /* count number of lines */
339         mem= cu->str;
340         slen = strlen(mem);
341         cu->lines= 1;
342         for (i= 0; i<=slen; i++, mem++) {
343                 ascii = *mem;
344                 if(ascii== '\n' || ascii== '\r') cu->lines++;
345         }
346
347         /* calc offset and rotation of each char */
348         ct = chartransdata =
349                 (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");
350         linedata= MEM_mallocN(sizeof(float)*cu->lines,"buildtext2");
351         linedata2= MEM_mallocN(sizeof(float)*cu->lines,"buildtext2");
352         xof= cu->xof;
353         yof= cu->yof;
354
355         xtrax= 0.5f*cu->spacing-0.5f;
356         linedist= cu->linedist;
357
358         for (i = 0 ; i<=slen ; i++) {
359                 ascii = cu->str[i];
360                 if(ascii== '\n' || ascii== '\r' || ascii==0) {
361                         ct->xof= xof;
362                         ct->yof= yof;
363                         ct->linenr= lnr;
364                         ct->charnr= cnr;
365                         
366                         /* only empty lines are allowed smaller than 1 */
367 //                      if( linedist<1.0) {
368 //                              if(i<slen && (cu->str[i+1]=='\r' || cu->str[i+1]=='\n')) yof-= linedist;
369 //                              else yof-= 1.0;
370 //                      }
371 //                      else
372                         yof-= linedist;
373                         
374                         maxlen= MAX2(maxlen, xof);
375                         linedata[lnr]= xof;
376                         linedata2[lnr]= cnr;
377                         xof= cu->xof;
378                         lnr++;
379                         cnr= 0;
380                 }
381                 else if(ascii==9) {     /* TAB */
382                         ct->xof= xof;
383                         ct->yof= yof;
384                         ct->linenr= lnr;
385                         ct->charnr= cnr++;
386
387                         tabfac= (xof-cu->xof+0.01f);
388                         tabfac= (float)(2.0*ceil(tabfac/2.0));
389                         xof= cu->xof+tabfac;
390                 }
391                 else {
392                         ct->xof= xof;
393                         ct->yof= yof;
394                         ct->linenr= lnr;
395                         ct->charnr= cnr++;
396
397                         xof += vfd->width[ascii] + xtrax;
398                 }
399                 ct++;
400         }
401
402         /* met alle fontsettings plekken letters berekenen */
403         if(cu->spacemode!=CU_LEFT/* && lnr>1*/) {
404                 ct= chartransdata;
405
406                 if(cu->spacemode==CU_RIGHT) {
407                         for(i=0;i<lnr;i++) linedata[i]= -linedata[i];
408                         for (i=0; i<=slen; i++) {
409                                 ct->xof+= linedata[ct->linenr];
410                                 ct++;
411                         }
412                 } else if(cu->spacemode==CU_MIDDLE) {
413                         for(i=0;i<lnr;i++) linedata[i]= -linedata[i]/2;
414                         for (i=0; i<=slen; i++) {
415                                 ct->xof+= linedata[ct->linenr];
416                                 ct++;
417                         }
418                 } else if(cu->spacemode==CU_FLUSH) {
419                         for(i=0;i<lnr;i++)
420                                 if(linedata2[i]>1)
421                                         linedata[i]= ((maxlen-linedata[i])/(linedata2[i]-1));
422                         for (i=0; i<=slen; i++) {
423                                 ct->xof+= (ct->charnr*linedata[ct->linenr])-maxlen/2;
424                                 ct++;
425                         }
426                 }
427         }
428
429         /* old alignment here, to spot the differences */
430 /*
431         if(cu->spacemode!=CU_LEFT && lnr>1) {
432                 ct= chartransdata;
433
434                 if(cu->spacemode==CU_RIGHT) {
435                         for(i=0;i<lnr;i++) linedata[i]= maxlen-linedata[i];
436                         for (i=0; i<=slen; i++) {
437                                 ct->xof+= linedata[ct->linenr];
438                                 ct++;
439                         }
440                 } else if(cu->spacemode==CU_MIDDLE) {
441                         for(i=0;i<lnr;i++) linedata[i]= (maxlen-linedata[i])/2;
442                         for (i=0; i<=slen; i++) {
443                                 ct->xof+= linedata[ct->linenr];
444                                 ct++;
445                         }
446                 } else if(cu->spacemode==CU_FLUSH) {
447                         for(i=0;i<lnr;i++)
448                                 if(linedata2[i]>1)
449                                         linedata[i]= (maxlen-linedata[i])/(linedata2[i]-1);
450                         for (i=0; i<=slen; i++) {
451                                 ct->xof+= ct->charnr*linedata[ct->linenr];
452                                 ct++;
453                         }
454                 }
455         }
456 */      
457         /* TEXT ON CURVE */
458         if(cu->textoncurve) {
459                 cucu= cu->textoncurve->data;
460                 
461                 oldflag= cucu->flag;
462                 cucu->flag |= (CU_PATH+CU_FOLLOW);
463                 
464                 if(cucu->path==0) calc_curvepath(cu->textoncurve);
465                 if(cucu->path) {
466                         
467
468                         Mat3CpyMat4(cmat, cu->textoncurve->obmat);
469                         sizefac= Normalise(cmat[0])/cu->fsize;
470                         
471                         minx=miny= 1.0e20f;
472                         maxx=maxy= -1.0e20f;
473                         ct= chartransdata;
474                         for (i=0; i<=slen; i++, ct++) {
475                                 if(minx>ct->xof) minx= ct->xof;
476                                 if(maxx<ct->xof) maxx= ct->xof;
477                                 if(miny>ct->yof) miny= ct->yof;
478                                 if(maxy<ct->yof) maxy= ct->yof;
479                         }
480                         
481                         /* we put the x-coordinaat exact at the curve, the y is rotated */
482                         
483                         /* length correction */
484                         distfac= sizefac*cucu->path->totdist/(maxx-minx);
485                         timeofs= 0.0;
486                         
487                         if(distfac > 1.0) {
488                                 /* path longer than text: spacemode involves */
489                                 distfac= 1.0f/distfac;
490                                 
491                                 if(cu->spacemode==CU_RIGHT) {
492                                         timeofs= 1.0f-distfac;
493                                 }
494                                 else if(cu->spacemode==CU_MIDDLE) {
495                                         timeofs= (1.0f-distfac)/2.0f;
496                                 }
497                                 else if(cu->spacemode==CU_FLUSH) distfac= 1.0f;
498                                 
499                         }
500                         else distfac= 1.0;
501                         
502                         distfac/= (maxx-minx);
503                         
504                         timeofs+= distfac*cu->xof;      /* not cyclic */
505                         
506                         ct= chartransdata;
507                         for (i=0; i<=slen; i++, ct++) {
508                                 
509                                 /* rotate around centre character */
510                                 ascii = cu->str[i];
511                                 dtime= distfac*0.35f*vfd->width[ascii]; /* why not 0.5? */
512                                 dtime= distfac*0.0f*vfd->width[ascii];  /* why not 0.5? */
513                                 
514                                 ctime= timeofs + distfac*( ct->xof - minx);
515                                 CLAMP(ctime, 0.0, 1.0);
516
517                                 /* calc the right loc AND the right rot separately */
518                                 /* vec, tvec need 4 items */
519                                 where_on_path(cu->textoncurve, ctime, vec, tvec);
520                                 where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec);
521                                 
522                                 VecMulf(vec, sizefac);
523                                 
524                                 ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0]));
525
526                                 si= (float)sin(ct->rot);
527                                 co= (float)cos(ct->rot);
528
529                                 yof= ct->yof;
530                                 
531                                 ct->xof= vec[0] + si*yof;
532                                 ct->yof= vec[1] + co*yof;
533                                 
534                         }
535                         cucu->flag= oldflag;
536                 }
537         }
538
539
540         if(mode==FO_CURSUP || mode==FO_CURSDOWN) {
541                 /* 2: curs up
542                    3: curs down */
543                 ct= chartransdata+cu->pos;
544                 
545                 if(mode==FO_CURSUP && ct->linenr==0);
546                 else if(mode==FO_CURSDOWN && ct->linenr==lnr);
547                 else {
548                         if(mode==FO_CURSUP) lnr= ct->linenr-1;
549                         else lnr= ct->linenr+1;
550                         cnr= ct->charnr;
551                         /* seek for char with lnr en cnr */
552                         cu->pos= 0;
553                         ct= chartransdata;
554                         for (i= 0; i<slen; i++) {
555                                 if(ct->linenr==lnr) {
556                                         if(ct->charnr==cnr) break;
557                                         if( (ct+1)->charnr==0) break;
558                                 }
559                                 else if(ct->linenr>lnr) break;
560                                 cu->pos++;
561                                 ct++;
562                         }
563                 }
564         }
565         
566         /* cursor first */
567         if(ob==G.obedit) {
568                 ct= chartransdata+cu->pos;
569                 si= (float)sin(ct->rot);
570                 co= (float)cos(ct->rot);
571                                 
572                 f= G.textcurs[0];
573                 
574                 f[0]= cu->fsize*(-0.1f*co + ct->xof);
575                 f[1]= cu->fsize*(0.1f*si + ct->yof);
576                 
577                 f[2]= cu->fsize*(0.1f*co + ct->xof);
578                 f[3]= cu->fsize*(-0.1f*si + ct->yof);
579                 
580                 f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof);
581                 f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof);
582                 
583                 f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof);
584                 f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof);
585                 
586         }
587
588         if(mode==0) {
589                 /* make nurbdata */
590                 
591                 freeNurblist(&cu->nurb);
592                 
593                 ct= chartransdata;
594                 for (i= 0; i<slen; i++) {
595                         ascii = cu->str[i];
596                         buildchar(cu, ascii, ct->xof, ct->yof, ct->rot);
597                         ct++;
598                 }
599         }
600
601         MEM_freeN(linedata);
602         MEM_freeN(linedata2);
603
604         if(mode==FO_DUPLI) {
605                 return chartransdata;
606         }
607
608         MEM_freeN(chartransdata);
609         return 0;
610 }
611
612
613 /* ***************** DUPLI  ***************** */
614
615 static Object *find_family_object(Object **obar, char *family, char ch)
616 {
617         Object *ob;
618         int flen;
619         
620         if( obar[ch] ) return obar[ch];
621         
622         flen= strlen(family);
623         
624         ob= G.main->object.first;
625         while(ob) {
626                 if( ob->id.name[flen+2]==ch ) {
627                         if( strncmp(ob->id.name+2, family, flen)==0 ) break;
628                 }
629                 ob= ob->id.next;
630         }
631         
632         obar[ch]= ob;
633         
634         return ob;
635 }
636
637
638 void font_duplilist(Object *par)
639 {
640         extern ListBase duplilist;
641         Object *ob, *newob, *obar[256];
642         Curve *cu;
643         struct chartrans *ct, *chartransdata;
644         float vec[3], pmat[4][4], fsize, xof, yof;
645         int slen, a;
646         
647         Mat4CpyMat4(pmat, par->obmat);
648
649         /* in par the family name is stored, use this to find the other objects */
650
651         chartransdata= text_to_curve(par, FO_DUPLI);
652         if(chartransdata==0) return;
653         
654         memset(obar, 0, 256*4);
655         
656         cu= par->data;
657         slen= strlen(cu->str);
658         fsize= cu->fsize;
659         xof= cu->xof;
660         yof= cu->yof;
661         
662         ct= chartransdata;
663         set_displist_onlyzero(1);
664
665         for(a=0; a<slen; a++, ct++) {
666         
667                 ob= find_family_object(obar, cu->family, cu->str[a]);
668                 if(ob) {
669                         
670                         makeDispList(ob);
671                         
672                         vec[0]= fsize*(ct->xof - xof);
673                         vec[1]= fsize*(ct->yof - yof);
674                         vec[2]= 0.0;
675         
676                         Mat4MulVecfl(pmat, vec);
677                         
678                         newob= MEM_mallocN(sizeof(Object), "newobj dupli");
679                         memcpy(newob, ob, sizeof(Object));
680                         newob->flag |= OB_FROMDUPLI;
681                         newob->id.newid= (ID *)par;             /* keep duplicator */
682                         newob->totcol= par->totcol;     /* for give_current_material */
683                         
684                         Mat4CpyMat4(newob->obmat, par->obmat);
685                         VECCOPY(newob->obmat[3], vec);
686                         
687                         newob->parent= 0;
688                         newob->track= 0;
689                         
690                         BLI_addtail(&duplilist, newob);
691                 }
692                 
693         }
694         set_displist_onlyzero(0);
695         MEM_freeN(chartransdata);
696 }