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