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