Quite a large one this time... but now we have:
[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                 }
145                 
146                 if (pf) {
147 #ifdef WITH_FREETYPE2
148                         vfont->data= BLI_vfontdata_from_freetypefont(pf);
149 #else
150                         vfont->data= BLI_vfontdata_from_psfont(pf);
151 #endif                  
152                         if (pf != vfont->packedfile) {
153                                 freePackedFile(pf);
154                         }
155                 }
156         }
157         
158         return vfont->data;     
159 }
160
161 VFont *load_vfont(char *name)
162 {
163         char filename[FILE_MAXFILE];
164         VFont *vfont= NULL;
165         PackedFile *pf;
166         int is_builtin;
167         
168         if (BLI_streq(name, "<builtin>")) {
169                 strcpy(filename, name);
170                 
171                 pf= get_builtin_packedfile();
172                 is_builtin= 1;
173         } else {
174                 char dir[FILE_MAXDIR];
175                 
176                 strcpy(dir, name);
177                 BLI_splitdirstring(dir, filename);
178
179                 pf= newPackedFile(name);
180                 is_builtin= 0;
181         }
182
183         if (pf) {
184                 VFontData *vfd;
185                 
186                 waitcursor(1);
187
188 #ifdef WITH_FREETYPE2
189                 vfd= BLI_vfontdata_from_freetypefont(pf);
190 #else
191                 vfd= BLI_vfontdata_from_psfont(pf);
192 #endif                  
193                 
194                 if (vfd) {
195                         vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
196                         vfont->data = vfd;
197                         
198                         BLI_strncpy(vfont->name, name, sizeof(vfont->name));
199
200                         // if autopack is on store the packedfile in de font structure
201                         if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
202                                 vfont->packedfile = pf;
203                         }
204                 }
205                 if (!vfont || vfont->packedfile != pf) {
206                         freePackedFile(pf);
207                 }
208         
209                 waitcursor(0);
210         }
211         
212         return vfont;
213 }
214
215 static void buildchar(Curve *cu, unsigned char ascii, float ofsx, float ofsy, float rot)
216 {
217         BezTriple *bezt1, *bezt2;
218         Nurb *nu1, *nu2;
219         float *fp, fsize, shear, x, si, co;
220         VFontData *vfd;
221         int i;
222
223         vfd= vfont_get_data(cu->vfont); 
224         if (!vfd) return;
225         
226         /* make a copy at distance ofsx,ofsy with shear*/
227         fsize= cu->fsize;
228         shear= cu->shear;
229         si= (float)sin(rot);
230         co= (float)cos(rot);
231
232         nu1 = vfd->nurbsbase[ascii].first;
233         while(nu1)
234         {
235                 bezt1 = nu1->bezt;
236                 if (bezt1){
237                         nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb");
238                         if (nu2 == 0) break;
239                         memcpy(nu2, nu1, sizeof(struct Nurb));
240                         nu2->resolu= cu->resolu;
241                         nu2->bp = 0;
242                         nu2->knotsu = nu2->knotsv = 0;
243                         nu2->flag= CU_SMOOTH;
244                         /* nu2->trim.first = 0; */
245                         /* nu2->trim.last = 0; */
246                         i = nu2->pntsu;
247
248                         bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2"); 
249                         if (bezt2 == 0){
250                                 MEM_freeN(nu2);
251                                 break;
252                         }
253                         memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
254                         nu2->bezt = bezt2;
255                         
256                         if (shear != 0.0) {
257                                 bezt2 = nu2->bezt;
258                                 
259                                 for (i= nu2->pntsu; i > 0; i--) {
260                                         bezt2->vec[0][0] += shear * bezt2->vec[0][1];
261                                         bezt2->vec[1][0] += shear * bezt2->vec[1][1];
262                                         bezt2->vec[2][0] += shear * bezt2->vec[2][1];
263                                         bezt2++;
264                                 }
265                         }
266                         if(rot!=0.0) {
267                                 bezt2= nu2->bezt;
268                                 for (i=nu2->pntsu; i > 0; i--) {
269                                         fp= bezt2->vec[0];
270                                         
271                                         x= fp[0];
272                                         fp[0]= co*x + si*fp[1];
273                                         fp[1]= -si*x + co*fp[1];
274                                         x= fp[3];
275                                         fp[3]= co*x + si*fp[4];
276                                         fp[4]= -si*x + co*fp[4];
277                                         x= fp[6];
278                                         fp[6]= co*x + si*fp[7];
279                                         fp[7]= -si*x + co*fp[7];
280
281                                         bezt2++;
282                                 }
283                         }
284                         bezt2 = nu2->bezt;
285                         
286                         for (i= nu2->pntsu; i > 0; i--) {
287                                 fp= bezt2->vec[0];
288
289                                 fp[0]= (fp[0]+ofsx)*fsize;
290                                 fp[1]= (fp[1]+ofsy)*fsize;
291                                 fp[3]= (fp[3]+ofsx)*fsize;
292                                 fp[4]= (fp[4]+ofsy)*fsize;
293                                 fp[6]= (fp[6]+ofsx)*fsize;
294                                 fp[7]= (fp[7]+ofsy)*fsize;
295                                 bezt2++;
296                         }
297                         
298                         BLI_addtail(&(cu->nurb), nu2);
299                 }
300                 nu1 = nu1->next;
301         }
302 }
303
304
305 struct chartrans *text_to_curve(Object *ob, int mode) 
306 {
307         VFont *vfont;
308         VFontData *vfd;
309         Curve *cu, *cucu;
310         struct chartrans *chartransdata, *ct;
311         float distfac, tabfac, ctime, dtime, tvec[4], vec[4], rotvec[3], minx, maxx, miny, maxy;
312         float cmat[3][3], timeofs, si, co, sizefac;
313         float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2;
314         int i, slen, oldflag;
315         short cnr=0, lnr=0;
316         char ascii, *mem;
317
318         /* renark: do calculations including the trailing '\0' of a string
319            because the cursor can be at that location */
320
321         if(ob->type!=OB_FONT) return 0;
322
323         cu= ob->data;
324
325         vfont= cu->vfont;
326         if (vfont==0) return 0;
327         if (cu->str==0) return 0;
328
329         vfd= vfont_get_data(vfont);
330         if (!vfd) return 0;
331         
332         /* count number of lines */
333         mem= cu->str;
334         slen = strlen(mem);
335         cu->lines= 1;
336         for (i= 0; i<=slen; i++, mem++) {
337                 ascii = *mem;
338                 if(ascii== '\n' || ascii== '\r') cu->lines++;
339         }
340
341         /* calc offset and rotation of each char */
342         ct = chartransdata =
343                 (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");
344         linedata= MEM_mallocN(sizeof(float)*cu->lines,"buildtext2");
345         linedata2= MEM_mallocN(sizeof(float)*cu->lines,"buildtext2");
346         xof= cu->xof;
347         yof= cu->yof;
348
349         xtrax= 0.5f*cu->spacing-0.5f;
350         linedist= cu->linedist;
351
352         for (i = 0 ; i<=slen ; i++) {
353                 ascii = cu->str[i];
354                 if(ascii== '\n' || ascii== '\r' || ascii==0) {
355                         ct->xof= xof;
356                         ct->yof= yof;
357                         ct->linenr= lnr;
358                         ct->charnr= cnr;
359                         
360                         /* only empty lines are allowed smaller than 1 */
361 //                      if( linedist<1.0) {
362 //                              if(i<slen && (cu->str[i+1]=='\r' || cu->str[i+1]=='\n')) yof-= linedist;
363 //                              else yof-= 1.0;
364 //                      }
365 //                      else
366                         yof-= linedist;
367                         
368                         maxlen= MAX2(maxlen, xof);
369                         linedata[lnr]= xof;
370                         linedata2[lnr]= cnr;
371                         xof= cu->xof;
372                         lnr++;
373                         cnr= 0;
374                 }
375                 else if(ascii==9) {     /* TAB */
376                         ct->xof= xof;
377                         ct->yof= yof;
378                         ct->linenr= lnr;
379                         ct->charnr= cnr++;
380
381                         tabfac= (xof-cu->xof+0.01f);
382                         tabfac= (float)(2.0*ceil(tabfac/2.0));
383                         xof= cu->xof+tabfac;
384                 }
385                 else {
386                         ct->xof= xof;
387                         ct->yof= yof;
388                         ct->linenr= lnr;
389                         ct->charnr= cnr++;
390
391                         xof += vfd->width[ascii] + xtrax;
392                 }
393                 ct++;
394         }
395
396         /* met alle fontsettings plekken letters berekenen */
397         if(cu->spacemode!=CU_LEFT/* && lnr>1*/) {
398                 ct= chartransdata;
399
400                 if(cu->spacemode==CU_RIGHT) {
401                         for(i=0;i<lnr;i++) linedata[i]= -linedata[i];
402                         for (i=0; i<=slen; i++) {
403                                 ct->xof+= linedata[ct->linenr];
404                                 ct++;
405                         }
406                 } else if(cu->spacemode==CU_MIDDLE) {
407                         for(i=0;i<lnr;i++) linedata[i]= -linedata[i]/2;
408                         for (i=0; i<=slen; i++) {
409                                 ct->xof+= linedata[ct->linenr];
410                                 ct++;
411                         }
412                 } else if(cu->spacemode==CU_FLUSH) {
413                         for(i=0;i<lnr;i++)
414                                 if(linedata2[i]>1)
415                                         linedata[i]= ((maxlen-linedata[i])/(linedata2[i]-1));
416                         for (i=0; i<=slen; i++) {
417                                 ct->xof+= (ct->charnr*linedata[ct->linenr])-maxlen/2;
418                                 ct++;
419                         }
420                 }
421         }
422
423         /* old alignment here, to spot the differences */
424 /*
425         if(cu->spacemode!=CU_LEFT && lnr>1) {
426                 ct= chartransdata;
427
428                 if(cu->spacemode==CU_RIGHT) {
429                         for(i=0;i<lnr;i++) linedata[i]= maxlen-linedata[i];
430                         for (i=0; i<=slen; i++) {
431                                 ct->xof+= linedata[ct->linenr];
432                                 ct++;
433                         }
434                 } else if(cu->spacemode==CU_MIDDLE) {
435                         for(i=0;i<lnr;i++) linedata[i]= (maxlen-linedata[i])/2;
436                         for (i=0; i<=slen; i++) {
437                                 ct->xof+= linedata[ct->linenr];
438                                 ct++;
439                         }
440                 } else if(cu->spacemode==CU_FLUSH) {
441                         for(i=0;i<lnr;i++)
442                                 if(linedata2[i]>1)
443                                         linedata[i]= (maxlen-linedata[i])/(linedata2[i]-1);
444                         for (i=0; i<=slen; i++) {
445                                 ct->xof+= ct->charnr*linedata[ct->linenr];
446                                 ct++;
447                         }
448                 }
449         }
450 */      
451         /* TEXT ON CURVE */
452         if(cu->textoncurve) {
453                 cucu= cu->textoncurve->data;
454                 
455                 oldflag= cucu->flag;
456                 cucu->flag |= (CU_PATH+CU_FOLLOW);
457                 
458                 if(cucu->path==0) calc_curvepath(cu->textoncurve);
459                 if(cucu->path) {
460                         
461
462                         Mat3CpyMat4(cmat, cu->textoncurve->obmat);
463                         sizefac= Normalise(cmat[0])/cu->fsize;
464                         
465                         minx=miny= 1.0e20f;
466                         maxx=maxy= -1.0e20f;
467                         ct= chartransdata;
468                         for (i=0; i<=slen; i++, ct++) {
469                                 if(minx>ct->xof) minx= ct->xof;
470                                 if(maxx<ct->xof) maxx= ct->xof;
471                                 if(miny>ct->yof) miny= ct->yof;
472                                 if(maxy<ct->yof) maxy= ct->yof;
473                         }
474                         
475                         /* we put the x-coordinaat exact at the curve, the y is rotated */
476                         
477                         /* length correction */
478                         distfac= sizefac*cucu->path->totdist/(maxx-minx);
479                         timeofs= 0.0;
480                         
481                         if(distfac > 1.0) {
482                                 /* path longer than text: spacemode involves */
483                                 distfac= 1.0f/distfac;
484                                 
485                                 if(cu->spacemode==CU_RIGHT) {
486                                         timeofs= 1.0f-distfac;
487                                 }
488                                 else if(cu->spacemode==CU_MIDDLE) {
489                                         timeofs= (1.0f-distfac)/2.0f;
490                                 }
491                                 else if(cu->spacemode==CU_FLUSH) distfac= 1.0f;
492                                 
493                         }
494                         else distfac= 1.0;
495                         
496                         distfac/= (maxx-minx);
497                         
498                         timeofs+= distfac*cu->xof;      /* not cyclic */
499                         
500                         ct= chartransdata;
501                         for (i=0; i<=slen; i++, ct++) {
502                                 
503                                 /* rotate around centre character */
504                                 ascii = cu->str[i];
505                                 dtime= distfac*0.35f*vfd->width[ascii]; /* why not 0.5? */
506                                 dtime= distfac*0.0f*vfd->width[ascii];  /* why not 0.5? */
507                                 
508                                 ctime= timeofs + distfac*( ct->xof - minx);
509                                 CLAMP(ctime, 0.0, 1.0);
510
511                                 /* calc the right loc AND the right rot separately */
512                                 where_on_path(cu->textoncurve, ctime, vec, tvec);
513                                 where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec);
514                                 
515                                 VecMulf(vec, sizefac);
516                                 
517                                 ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0]));
518
519                                 si= (float)sin(ct->rot);
520                                 co= (float)cos(ct->rot);
521
522                                 yof= ct->yof;
523                                 
524                                 ct->xof= vec[0] + si*yof;
525                                 ct->yof= vec[1] + co*yof;
526                                 
527                         }
528                         cucu->flag= oldflag;
529                 }
530         }
531
532
533         if(mode==FO_CURSUP || mode==FO_CURSDOWN) {
534                 /* 2: curs up
535                    3: curs down */
536                 ct= chartransdata+cu->pos;
537                 
538                 if(mode==FO_CURSUP && ct->linenr==0);
539                 else if(mode==FO_CURSDOWN && ct->linenr==lnr);
540                 else {
541                         if(mode==FO_CURSUP) lnr= ct->linenr-1;
542                         else lnr= ct->linenr+1;
543                         cnr= ct->charnr;
544                         /* seek for char with lnr en cnr */
545                         cu->pos= 0;
546                         ct= chartransdata;
547                         for (i= 0; i<slen; i++) {
548                                 if(ct->linenr==lnr) {
549                                         if(ct->charnr==cnr) break;
550                                         if( (ct+1)->charnr==0) break;
551                                 }
552                                 else if(ct->linenr>lnr) break;
553                                 cu->pos++;
554                                 ct++;
555                         }
556                 }
557         }
558         
559         /* cursor first */
560         if(ob==G.obedit) {
561                 ct= chartransdata+cu->pos;
562                 si= (float)sin(ct->rot);
563                 co= (float)cos(ct->rot);
564                                 
565                 f= G.textcurs[0];
566                 
567                 f[0]= cu->fsize*(-0.1f*co + ct->xof);
568                 f[1]= cu->fsize*(0.1f*si + ct->yof);
569                 
570                 f[2]= cu->fsize*(0.1f*co + ct->xof);
571                 f[3]= cu->fsize*(-0.1f*si + ct->yof);
572                 
573                 f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof);
574                 f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof);
575                 
576                 f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof);
577                 f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof);
578                 
579         }
580
581         if(mode==0) {
582                 /* make nurbdata */
583                 
584                 freeNurblist(&cu->nurb);
585                 
586                 ct= chartransdata;
587                 for (i= 0; i<slen; i++) {
588                         ascii = cu->str[i];
589                         buildchar(cu, ascii, ct->xof, ct->yof, ct->rot);
590                         ct++;
591                 }
592         }
593
594         MEM_freeN(linedata);
595         MEM_freeN(linedata2);
596
597         if(mode==FO_DUPLI) {
598                 return chartransdata;
599         }
600
601         MEM_freeN(chartransdata);
602         return 0;
603 }
604
605
606 /* ***************** DUPLI  ***************** */
607
608 static Object *find_family_object(Object **obar, char *family, char ch)
609 {
610         Object *ob;
611         int flen;
612         
613         if( obar[ch] ) return obar[ch];
614         
615         flen= strlen(family);
616         
617         ob= G.main->object.first;
618         while(ob) {
619                 if( ob->id.name[flen+2]==ch ) {
620                         if( strncmp(ob->id.name+2, family, flen)==0 ) break;
621                 }
622                 ob= ob->id.next;
623         }
624         
625         obar[ch]= ob;
626         
627         return ob;
628 }
629
630
631 void font_duplilist(Object *par)
632 {
633         extern ListBase duplilist;
634         Object *ob, *newob, *obar[256];
635         Curve *cu;
636         struct chartrans *ct, *chartransdata;
637         float vec[3], pmat[4][4], fsize, xof, yof;
638         int slen, a;
639         
640         Mat4CpyMat4(pmat, par->obmat);
641
642         /* in par the family name is stored, use this to find the other objects */
643
644         chartransdata= text_to_curve(par, FO_DUPLI);
645         if(chartransdata==0) return;
646         
647         memset(obar, 0, 256*4);
648         
649         cu= par->data;
650         slen= strlen(cu->str);
651         fsize= cu->fsize;
652         xof= cu->xof;
653         yof= cu->yof;
654         
655         ct= chartransdata;
656         set_displist_onlyzero(1);
657
658         for(a=0; a<slen; a++, ct++) {
659         
660                 ob= find_family_object(obar, cu->family, cu->str[a]);
661                 if(ob) {
662                         
663                         makeDispList(ob);
664                         
665                         vec[0]= fsize*(ct->xof - xof);
666                         vec[1]= fsize*(ct->yof - yof);
667                         vec[2]= 0.0;
668         
669                         Mat4MulVecfl(pmat, vec);
670                         
671                         newob= MEM_mallocN(sizeof(Object), "newobj dupli");
672                         memcpy(newob, ob, sizeof(Object));
673                         newob->flag |= OB_FROMDUPLI;
674                         newob->id.newid= (ID *)par;             /* keep duplicator */
675                         newob->totcol= par->totcol;     /* for give_current_material */
676                         
677                         Mat4CpyMat4(newob->obmat, par->obmat);
678                         VECCOPY(newob->obmat[3], vec);
679                         
680                         newob->parent= 0;
681                         newob->track= 0;
682                         
683                         BLI_addtail(&duplilist, newob);
684                 }
685                 
686         }
687         set_displist_onlyzero(0);
688         MEM_freeN(chartransdata);
689 }