Initial commit for new text object.
[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 #define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
73  
74 struct SelBox *selboxes= NULL;
75
76 struct chartrans {
77         float xof, yof;
78         float rot;
79         short linenr,charnr;
80         char dobreak;
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\n");
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                         if(!pf) {
146                                 printf("Font file doesn't exist: %s\n", vfont->name);
147
148                                 strcpy(vfont->name, "<builtin>");
149                                 pf= get_builtin_packedfile();
150                         }
151                 }
152                 
153                 if (pf) {
154 #ifdef WITH_FREETYPE2
155                         vfont->data= BLI_vfontdata_from_freetypefont(pf);
156 #else
157                         vfont->data= BLI_vfontdata_from_psfont(pf);
158 #endif                  
159                         if (pf != vfont->packedfile) {
160                                 freePackedFile(pf);
161                         }
162                 }
163         }
164         
165         return vfont->data;     
166 }
167
168 VFont *load_vfont(char *name)
169 {
170         char filename[FILE_MAXFILE];
171         VFont *vfont= NULL;
172         PackedFile *pf;
173         int is_builtin;
174         
175         if (BLI_streq(name, "<builtin>")) {
176                 strcpy(filename, name);
177                 
178                 pf= get_builtin_packedfile();
179                 is_builtin= 1;
180         } else {
181                 char dir[FILE_MAXDIR];
182                 
183                 strcpy(dir, name);
184                 BLI_splitdirstring(dir, filename);
185
186                 pf= newPackedFile(name);
187                 is_builtin= 0;
188         }
189
190         if (pf) {
191                 VFontData *vfd;
192                 
193                 waitcursor(1);
194
195 #ifdef WITH_FREETYPE2
196                 vfd= BLI_vfontdata_from_freetypefont(pf);
197 #else
198                 vfd= BLI_vfontdata_from_psfont(pf);
199 #endif                  
200                 
201                 if (vfd) {
202                         vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
203                         vfont->data = vfd;
204                         
205                         BLI_strncpy(vfont->name, name, sizeof(vfont->name));
206
207                         // if autopack is on store the packedfile in de font structure
208                         if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
209                                 vfont->packedfile = pf;
210                         }
211                 }
212                 if (!vfont || vfont->packedfile != pf) {
213                         freePackedFile(pf);
214                 }
215         
216                 waitcursor(0);
217         }
218         
219         return vfont;
220 }
221
222 static VFont *which_vfont(Curve *cu, CharInfo *info)
223 {
224         switch(info->flag & CU_STYLE) {
225                 case CU_BOLD:
226                         return(cu->vfontb);
227                 case CU_ITALIC:
228                         return(cu->vfonti);
229                 case (CU_BOLD|CU_ITALIC):
230                         return(cu->vfontbi);
231                 default:
232                         return(cu->vfont);
233         }                       
234 }
235
236 static void buildchar(Curve *cu, unsigned char ascii, CharInfo *info, float ofsx, float ofsy, float rot, int charidx)
237 {
238         BezTriple *bezt1, *bezt2;
239         Nurb *nu1, *nu2;
240         float *fp, fsize, shear, x, si, co;
241         VFontData *vfd;
242         int i, sel=0;
243
244         vfd= vfont_get_data(which_vfont(cu, info));     
245         if (!vfd) return;
246
247         if (cu->selend < cu->selstart) {
248                 if ((charidx >= (cu->selend)) && (charidx <= (cu->selstart-2)))
249                         sel= 1;
250         }
251         else {
252                 if ((charidx >= (cu->selstart-1)) && (charidx <= (cu->selend-1)))
253                         sel= 1;
254         }
255
256         /* make a copy at distance ofsx,ofsy with shear*/
257         fsize= cu->fsize;
258         shear= cu->shear;
259         si= (float)sin(rot);
260         co= (float)cos(rot);
261
262         nu1 = vfd->nurbsbase[ascii].first;
263         while(nu1)
264         {
265                 bezt1 = nu1->bezt;
266                 if (bezt1){
267                         nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb");
268                         if (nu2 == 0) break;
269                         memcpy(nu2, nu1, sizeof(struct Nurb));
270                         nu2->resolu= cu->resolu;
271                         nu2->bp = 0;
272                         nu2->knotsu = nu2->knotsv = 0;
273                         nu2->flag= CU_SMOOTH;
274                         nu2->charidx = charidx;
275                         if (info->mat_nr) nu2->mat_nr= info->mat_nr-1;
276                         /* nu2->trim.first = 0; */
277                         /* nu2->trim.last = 0; */
278                         i = nu2->pntsu;
279
280                         bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2"); 
281                         if (bezt2 == 0){
282                                 MEM_freeN(nu2);
283                                 break;
284                         }
285                         memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
286                         nu2->bezt = bezt2;
287                         
288                         if (shear != 0.0) {
289                                 bezt2 = nu2->bezt;
290                                 
291                                 for (i= nu2->pntsu; i > 0; i--) {
292                                         bezt2->vec[0][0] += shear * bezt2->vec[0][1];
293                                         bezt2->vec[1][0] += shear * bezt2->vec[1][1];
294                                         bezt2->vec[2][0] += shear * bezt2->vec[2][1];
295                                         bezt2++;
296                                 }
297                         }
298                         if(rot!=0.0) {
299                                 bezt2= nu2->bezt;
300                                 for (i=nu2->pntsu; i > 0; i--) {
301                                         fp= bezt2->vec[0];
302                                         
303                                         x= fp[0];
304                                         fp[0]= co*x + si*fp[1];
305                                         fp[1]= -si*x + co*fp[1];
306                                         x= fp[3];
307                                         fp[3]= co*x + si*fp[4];
308                                         fp[4]= -si*x + co*fp[4];
309                                         x= fp[6];
310                                         fp[6]= co*x + si*fp[7];
311                                         fp[7]= -si*x + co*fp[7];
312
313                                         bezt2++;
314                                 }
315                         }
316                         bezt2 = nu2->bezt;
317
318                         for (i= nu2->pntsu; i > 0; i--) {
319                                 fp= bezt2->vec[0];
320
321                                 fp[0]= (fp[0]+ofsx)*fsize;
322                                 fp[1]= (fp[1]+ofsy)*fsize;
323                                 fp[3]= (fp[3]+ofsx)*fsize;
324                                 fp[4]= (fp[4]+ofsy)*fsize;
325                                 fp[6]= (fp[6]+ofsx)*fsize;
326                                 fp[7]= (fp[7]+ofsy)*fsize;
327                                 bezt2++;
328                         }
329                         
330                         BLI_addtail(&(cu->nurb), nu2);
331                 }
332                 
333                 nu1 = nu1->next;
334         }
335 }
336
337 int getselection(int *start, int *end)
338 {
339         Curve *cu;
340         
341         if (G.obedit==NULL || G.obedit->type != OB_FONT) return 0;
342         
343         cu= G.obedit->data;
344
345         if (cu->selstart == 0) return 0;
346         if (cu->selstart <= cu->selend) {
347                 *start = cu->selstart-1;
348                 *end = cu->selend-1;
349                 return 1;
350         }
351         else {
352                 *start = cu->selend;
353                 *end = cu->selstart-2;
354                 return -1;
355         }
356 }
357
358 struct chartrans *text_to_curve(Object *ob, int mode) 
359 {
360         VFont *vfont, *oldvfont;
361         VFontData *vfd;
362         Curve *cu, *cucu;
363         struct chartrans *chartransdata, *ct;
364         float distfac, tabfac, ctime, dtime, tvec[4], vec[4], rotvec[3], minx, maxx, miny, maxy;
365         float cmat[3][3], timeofs, si, co, sizefac;
366         float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3;
367         int i, slen, oldflag, j;
368         short cnr=0, lnr=0;
369         char ascii, *mem;
370         int outta;
371         float vecyo[3];
372         CharInfo *info;
373         float wsfac;
374         TextBox *tb;
375         int curbox;
376         int selstart, selend;
377         SelBox *sb;
378
379         /* renark: do calculations including the trailing '\0' of a string
380            because the cursor can be at that location */
381
382         if(ob->type!=OB_FONT) return 0;
383
384         cu= ob->data;
385         mem= cu->str;
386         slen = strlen(mem);     
387
388         if (cu->str==0) return 0;
389         if (cu->strinfo==NULL) {        /* old file */
390                 fprintf(stderr, "old file\n");
391                 cu->strinfo = MEM_callocN((slen+1) * sizeof(CharInfo), "strinfo compat");
392         }
393
394         /* calc offset and rotation of each char */
395         ct = chartransdata =
396                 (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");
397
398         /* We assume the worst case: 1 character per line (is freed at end anyway) */
399
400         linedata= MEM_mallocN(sizeof(float)*(slen+2),"buildtext2");
401         linedata2= MEM_mallocN(sizeof(float)*(slen+2),"buildtext3");
402         linedata3= MEM_mallocN(sizeof(float)*(slen+2),"buildtext4");    
403         
404         linedist= cu->linedist;
405         
406         xof= cu->xof + (cu->tb[0].x/cu->fsize);
407         yof= cu->yof + (cu->tb[0].y/cu->fsize);
408
409         xtrax= 0.5f*cu->spacing-0.5f;
410
411         oldvfont = NULL;
412
413         for (i=0; i<slen; i++) cu->strinfo[i].flag &= ~CU_WRAP;
414
415         if (selboxes) MEM_freeN(selboxes);
416         selboxes = NULL;
417         if (getselection(&selstart, &selend))
418                 selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes");
419
420         tb = &(cu->tb[0]);
421         curbox= 0;
422         for (i = 0 ; i<=slen ; i++) {
423         makebreak:
424                 ascii = cu->str[i];
425                 info = &(cu->strinfo[i]);
426                 vfont = which_vfont(cu, info);
427         if (vfont==0) return 0;
428         if (vfont != oldvfont) {
429                 vfd= vfont_get_data(vfont);
430                 oldvfont = vfont;
431         }
432         if (!vfd) return 0;     
433         if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+vfd->width[ascii])*cu->fsize) > tb->w) {
434 //              fprintf(stderr, "linewidth exceeded: %c%c%c...\n", cu->str[i], cu->str[i+1], cu->str[i+2]);
435                 for (j=i; j && (cu->str[j] != '\n') && (cu->str[j] != '\r') && (chartransdata[j].dobreak==0); j--) {
436                         if (cu->str[j]==' ') {
437                                         ct -= (i-(j-1));
438                                         cnr -= (i-(j-1));
439                                         i = j-1;
440                                         xof = ct->xof;
441                                         ct[1].dobreak = 1;
442                                         cu->strinfo[i+1].flag |= CU_WRAP;
443                                         goto makebreak;
444                         }
445                         if (chartransdata[j].dobreak) {
446 //                              fprintf(stderr, "word too long: %c%c%c...\n", cu->str[j], cu->str[j+1], cu->str[j+2]);
447                                 ct->dobreak= 1;
448                                 cu->strinfo[i+1].flag |= CU_WRAP;
449                                 ct -= 1;
450                                 cnr -= 1;
451                                 i--;
452                                 xof = ct->xof;
453                                 goto makebreak;
454                         }
455                 }
456         }
457                 if(ascii== '\n' || ascii== '\r' || ascii==0 || ct->dobreak) {
458                         ct->xof= xof;
459                         ct->yof= yof;
460                         ct->linenr= lnr;
461                         ct->charnr= cnr;
462                         
463                         yof-= linedist;
464                         
465                         maxlen= MAX2(maxlen, (xof-tb->x/cu->fsize));
466                         linedata[lnr]= xof-tb->x/cu->fsize;
467                         linedata2[lnr]= cnr;
468                         linedata3[lnr]= tb->w/cu->fsize;
469                         
470                         if ( (tb->h != 0.0) &&
471                              ((-(yof-(tb->y/cu->fsize))) > ((tb->h/cu->fsize)-(linedist*cu->fsize))) &&
472                              (cu->totbox > (curbox+1)) ) {
473                                 maxlen= 0;
474                                 tb++;
475                                 curbox++;
476                                 yof= cu->yof + tb->y/cu->fsize;
477                         }
478                         
479                         xof= cu->xof + (tb->x/cu->fsize);
480                         lnr++;
481                         cnr= 0;
482                 }
483                 else if(ascii==9) {     /* TAB */
484                         ct->xof= xof;
485                         ct->yof= yof;
486                         ct->linenr= lnr;
487                         ct->charnr= cnr++;
488
489                         tabfac= (xof-cu->xof+0.01f);
490                         tabfac= (float)(2.0*ceil(tabfac/2.0));
491                         xof= cu->xof+tabfac;
492                 }
493                 else {
494                         ct->xof= xof;
495                         ct->yof= yof;
496                         ct->linenr= lnr;
497                         ct->charnr= cnr++;
498
499                         if (selboxes && (i>=selstart) && (i<=selend)) {
500                         sb = &(selboxes[i-selstart]);
501                         sb->y = yof*cu->fsize-linedist*cu->fsize*0.1;
502                         sb->h = linedist*cu->fsize;
503                         sb->w = xof*cu->fsize;
504                 }
505         
506                         if (ascii==32) wsfac = cu->wordspace; else wsfac = 1.0;
507                         xof += (vfd->width[ascii]*wsfac*(1.0+(info->kern/20.0)) ) + xtrax;
508                         
509                         if (selboxes && (i>=selstart) && (i<=selend)) sb->w = (xof*cu->fsize) - sb->w;
510                 }
511                 ct++;
512         }
513         
514
515         
516         cu->lines= 1;
517         ct= chartransdata;
518         for (i= 0; i<=slen; i++, mem++, ct++) {
519                 ascii = *mem;
520                 if(ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++;
521         }       
522
523         // linedata is now: width of line
524         // linedata2 is now: number of characters
525         // linedata3 is now: maxlen of that line
526
527         if(cu->spacemode!=CU_LEFT && lnr>1) {
528                 ct= chartransdata;
529
530                 if(cu->spacemode==CU_RIGHT) {
531                         for(i=0;i<lnr;i++) linedata[i]= linedata3[i]-linedata[i];
532                         for (i=0; i<=slen; i++) {
533                                 ct->xof+= linedata[ct->linenr];
534                                 ct++;
535                         }
536                 } else if(cu->spacemode==CU_MIDDLE) {
537                         for(i=0;i<lnr;i++) linedata[i]= (linedata3[i]-linedata[i])/2;
538                         for (i=0; i<=slen; i++) {
539                                 ct->xof+= linedata[ct->linenr];
540                                 ct++;
541                         }
542                 } else if(cu->spacemode==CU_FLUSH) {
543                         for(i=0;i<lnr;i++)
544                                 if(linedata2[i]>1)
545                                         linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1);
546                         for (i=0; i<=slen; i++) {
547                                 for (j=i; (cu->str[j]) && (cu->str[j]!='\n') && 
548                                           (cu->str[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
549                                 if ((cu->str[j]!='\r') && (cu->str[j]!='\n')) {
550                                         ct->xof+= ct->charnr*linedata[ct->linenr];
551                                 }
552                                 ct++;
553                         }
554                 }
555         }
556         
557         /* TEXT ON CURVE */
558         if(cu->textoncurve) {
559                 cucu= cu->textoncurve->data;
560                 
561                 oldflag= cucu->flag;
562                 cucu->flag |= (CU_PATH+CU_FOLLOW);
563                 
564                 if(cucu->path==0) calc_curvepath(cu->textoncurve);
565                 if(cucu->path) {
566                         
567
568                         Mat3CpyMat4(cmat, cu->textoncurve->obmat);
569                         sizefac= Normalise(cmat[0])/cu->fsize;
570                         
571                         minx=miny= 1.0e20f;
572                         maxx=maxy= -1.0e20f;
573                         ct= chartransdata;
574                         for (i=0; i<=slen; i++, ct++) {
575                                 if(minx>ct->xof) minx= ct->xof;
576                                 if(maxx<ct->xof) maxx= ct->xof;
577                                 if(miny>ct->yof) miny= ct->yof;
578                                 if(maxy<ct->yof) maxy= ct->yof;
579                         }
580                         
581                         /* we put the x-coordinaat exact at the curve, the y is rotated */
582                         
583                         /* length correction */
584                         distfac= sizefac*cucu->path->totdist/(maxx-minx);
585                         timeofs= 0.0;
586                         
587                         if(distfac > 1.0) {
588                                 /* path longer than text: spacemode involves */
589                                 distfac= 1.0f/distfac;
590                                 
591                                 if(cu->spacemode==CU_RIGHT) {
592                                         timeofs= 1.0f-distfac;
593                                 }
594                                 else if(cu->spacemode==CU_MIDDLE) {
595                                         timeofs= (1.0f-distfac)/2.0f;
596                                 }
597                                 else if(cu->spacemode==CU_FLUSH) distfac= 1.0f;
598                                 
599                         }
600                         else distfac= 1.0;
601                         
602                         distfac/= (maxx-minx);
603                         
604                         timeofs+= distfac*cu->xof;      /* not cyclic */
605                         
606                         ct= chartransdata;
607                         for (i=0; i<=slen; i++, ct++) {
608                                 
609                                 /* rotate around centre character */
610                                 ascii = cu->str[i];
611                                 dtime= distfac*0.35f*vfd->width[ascii]; /* why not 0.5? */
612                                 dtime= distfac*0.0f*vfd->width[ascii];  /* why not 0.5? */
613                                 
614                                 ctime= timeofs + distfac*( ct->xof - minx);
615                                 CLAMP(ctime, 0.0, 1.0);
616
617                                 /* calc the right loc AND the right rot separately */
618                                 /* vec, tvec need 4 items */
619                                 where_on_path(cu->textoncurve, ctime, vec, tvec);
620                                 where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec);
621                                 
622                                 VecMulf(vec, sizefac);
623                                 
624                                 ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0]));
625
626                                 si= (float)sin(ct->rot);
627                                 co= (float)cos(ct->rot);
628
629                                 yof= ct->yof;
630                                 
631                                 ct->xof= vec[0] + si*yof;
632                                 ct->yof= vec[1] + co*yof;
633                                 
634                         }
635                         cucu->flag= oldflag;
636                 }
637         }
638
639         if (selboxes) {
640                 ct= chartransdata;
641                 for (i=0; i<=selend; i++, ct++) {
642                         if (i>=selstart) {
643                                 selboxes[i-selstart].x = ct->xof*cu->fsize;
644                         }
645                 }
646         }
647
648         if(mode==FO_CURSUP || mode==FO_CURSDOWN || mode==FO_PAGEUP || mode==FO_PAGEDOWN) {
649                 /* 2: curs up
650                    3: curs down */
651                 ct= chartransdata+cu->pos;
652                 
653                 if((mode==FO_CURSUP || mode==FO_PAGEUP) && ct->linenr==0);
654                 else if((mode==FO_CURSDOWN || mode==FO_PAGEDOWN) && ct->linenr==lnr);
655                 else {
656                         switch(mode) {
657                                 case FO_CURSUP:         lnr= ct->linenr-1; break;
658                                 case FO_CURSDOWN:       lnr= ct->linenr+1; break;
659                                 case FO_PAGEUP:         lnr= ct->linenr-10; break;
660                                 case FO_PAGEDOWN:       lnr= ct->linenr+10; break;
661                         }
662                         cnr= ct->charnr;
663                         /* seek for char with lnr en cnr */
664                         cu->pos= 0;
665                         ct= chartransdata;
666                         for (i= 0; i<slen; i++) {
667                                 if(ct->linenr==lnr) {
668                                         if(ct->charnr==cnr) break;
669                                         if( (ct+1)->charnr==0) break;
670                                 }
671                                 else if(ct->linenr>lnr) break;
672                                 cu->pos++;
673                                 ct++;
674                         }
675                 }
676         }
677         
678         /* cursor first */
679         if(ob==G.obedit) {
680                 ct= chartransdata+cu->pos;
681                 si= (float)sin(ct->rot);
682                 co= (float)cos(ct->rot);
683                                 
684                 f= G.textcurs[0];
685                 
686                 f[0]= cu->fsize*(-0.1f*co + ct->xof);
687                 f[1]= cu->fsize*(0.1f*si + ct->yof);
688                 
689                 f[2]= cu->fsize*(0.1f*co + ct->xof);
690                 f[3]= cu->fsize*(-0.1f*si + ct->yof);
691                 
692                 f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof);
693                 f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof);
694                 
695                 f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof);
696                 f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof);
697                 
698         }
699
700         if (mode == FO_SELCHANGE) {
701                 MEM_freeN(chartransdata);
702                 MEM_freeN(linedata);
703                 MEM_freeN(linedata2);           
704                 MEM_freeN(linedata3);
705                 return NULL;
706         }
707
708         if(mode==0) {
709                 /* make nurbdata */
710                 
711                 freeNurblist(&cu->nurb);
712                 
713                 ct= chartransdata;
714                 if (cu->sepchar==0) {
715                 for (i= 0; i<slen; i++) {
716                         ascii = cu->str[i];
717                         info = &(cu->strinfo[i]);
718                                 buildchar(cu, ascii, info, ct->xof, ct->yof, ct->rot, i);
719                         ct++;
720                 }
721                 }
722                 else {
723                 outta = 0;
724                 for (i= 0; (i<slen) && (outta==0); i++) {
725                         ascii = cu->str[i];
726                         info = &(cu->strinfo[i]);
727                                 if (cu->sepchar == (i+1)) {
728                                         cu->str[0] = ascii;
729                                         cu->str[1] = 0;
730                                         cu->strinfo[0]= *info;
731                                         cu->pos = 1;
732                                         cu->len = 1;
733                                         vecyo[0] = ct->xof;
734                                         vecyo[1] = ct->yof;
735                                         vecyo[2] = 0;
736                                         Mat4MulVecfl(ob->obmat, vecyo);
737                                         VECCOPY(ob->loc, vecyo);
738                                         outta = 1;
739                                         cu->sepchar = 0;
740                                 }
741                         ct++;
742                 }
743         }
744         }
745
746         MEM_freeN(linedata);
747         MEM_freeN(linedata2);
748         MEM_freeN(linedata3);   
749
750         if(mode==FO_DUPLI) {
751                 return chartransdata;
752         }
753
754         MEM_freeN(chartransdata);
755         return 0;
756 }
757
758
759 /* ***************** DUPLI  ***************** */
760
761 static Object *find_family_object(Object **obar, char *family, char ch)
762 {
763         Object *ob;
764         int flen;
765         
766         if( obar[ch] ) return obar[ch];
767         
768         flen= strlen(family);
769         
770         ob= G.main->object.first;
771         while(ob) {
772                 if( ob->id.name[flen+2]==ch ) {
773                         if( strncmp(ob->id.name+2, family, flen)==0 ) break;
774                 }
775                 ob= ob->id.next;
776         }
777         
778         obar[ch]= ob;
779         
780         return ob;
781 }
782
783
784 void font_duplilist(Object *par)
785 {
786         extern ListBase duplilist;
787         Object *ob, *newob, *obar[256];
788         Curve *cu;
789         struct chartrans *ct, *chartransdata;
790         float vec[3], pmat[4][4], fsize, xof, yof;
791         int slen, a;
792         
793         Mat4CpyMat4(pmat, par->obmat);
794
795         /* in par the family name is stored, use this to find the other objects */
796
797         chartransdata= text_to_curve(par, FO_DUPLI);
798         if(chartransdata==0) return;
799         
800         memset(obar, 0, 256*4);
801         
802         cu= par->data;
803         slen= strlen(cu->str);
804         fsize= cu->fsize;
805         xof= cu->xof;
806         yof= cu->yof;
807         
808         ct= chartransdata;
809         set_displist_onlyzero(1);
810
811         for(a=0; a<slen; a++, ct++) {
812         
813                 ob= find_family_object(obar, cu->family, cu->str[a]);
814                 if(ob) {
815                         
816                         makeDispList(ob);
817                         
818                         vec[0]= fsize*(ct->xof - xof);
819                         vec[1]= fsize*(ct->yof - yof);
820                         vec[2]= 0.0;
821         
822                         Mat4MulVecfl(pmat, vec);
823                         
824                         newob= MEM_mallocN(sizeof(Object), "newobj dupli");
825                         memcpy(newob, ob, sizeof(Object));
826                         newob->flag |= OB_FROMDUPLI;
827                         newob->id.newid= (ID *)par;             /* keep duplicator */
828                         newob->totcol= par->totcol;     /* for give_current_material */
829                         
830                         Mat4CpyMat4(newob->obmat, par->obmat);
831                         VECCOPY(newob->obmat[3], vec);
832                         
833                         newob->parent= 0;
834                         newob->track= 0;
835                         
836                         BLI_addtail(&duplilist, newob);
837                 }
838                 
839         }
840         set_displist_onlyzero(0);
841         MEM_freeN(chartransdata);
842 }