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