Back to index

radiance  4R0+20100331
text.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: text.c,v 2.25 2004/03/30 16:13:01 schorsch Exp $";
00003 #endif
00004 /*
00005  *  text.c - functions for text patterns and mixtures.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include  "ray.h"
00011 #include  "paths.h"
00012 #include  "otypes.h"
00013 #include  "rtotypes.h"
00014 #include  "font.h"
00015 
00016 /*
00017  *     A text pattern is specified as the text (a file or line),
00018  *  the upper left anchor point, the right motion vector, the down
00019  *  motion vector, and the foreground and background brightness.
00020  *  For a file, the description is as follows:
00021  *
00022  *     modifier brighttext id
00023  *     2 fontfile textfile
00024  *     0
00025  *     11+
00026  *            Ax Ay Az
00027  *            Rx Ry Rz
00028  *            Dx Dy Dz
00029  *            foreground background
00030  *            [spacing]
00031  *
00032  *  For a single line, we use:
00033  *
00034  *     modifier brighttext id
00035  *     N+2 fontfile . This is a line with N words...
00036  *     0
00037  *     11+
00038  *            Ax Ay Az
00039  *            Rx Ry Rz
00040  *            Dx Dy Dz
00041  *            foreground background
00042  *            [spacing]
00043  *
00044  *  Colortext is identical, except colors are given rather than
00045  *  brightnesses.
00046  *
00047  *  Mixtext has foreground and background modifiers:
00048  *
00049  *     modifier mixtext id
00050  *     4+ foremod backmod fontfile text..
00051  *     0
00052  *     9+
00053  *            Ax Ay Az
00054  *            Rx Ry Rz
00055  *            Dx Dy Dz
00056  *            [spacing]
00057  */
00058 
00059 #define  fndx(m)     ((m)->otype==MIX_TEXT ? 2 : 0)
00060 #define  tndx(m)     ((m)->otype==MIX_TEXT ? 3 : 1)
00061 #define  sndx(m)     ((m)->otype==PAT_BTEXT ? 11 : \
00062                             (m)->otype==PAT_CTEXT ? 15 : 9)
00063 
00064 typedef struct tline {
00065        struct tline  *next;        /* pointer to next line */
00066        short  *spc;                /* character spacing */
00067        int  width;                 /* total line width */
00068                                    /* followed by the string */
00069 }  TLINE;
00070 
00071 #define  TLSTR(l)    ((char *)((l)+1))
00072 
00073 typedef struct {
00074        FVECT  right, down;         /* right and down unit vectors */
00075        FONT  *f;                   /* our font */
00076        TLINE  tl;                  /* line list */
00077 }  TEXT;
00078 
00079 static TLINE * tlalloc(char *s);
00080 static TEXT * gettext(OBJREC *tm);
00081 static int intext(FVECT p, OBJREC *m);
00082 static int inglyph(double x, double y, GLYPH *gl);
00083 
00084 
00085 extern int
00086 do_text(
00087        register OBJREC  *m,
00088        RAY  *r
00089 )
00090 {
00091        FVECT  v;
00092        int  foreground;
00093                             /* get transformed position */
00094        if (r->rox != NULL)
00095               multp3(v, r->rop, r->rox->b.xfm);
00096        else
00097               VCOPY(v, r->rop);
00098                             /* check if we are within a text glyph */
00099        foreground = intext(v, m);
00100                             /* modify */
00101        if (m->otype == MIX_TEXT) {
00102               OBJECT  omod;
00103               char  *modname = m->oargs.sarg[foreground ? 0 : 1];
00104               if (!strcmp(modname, VOIDID))
00105                      omod = OVOID;
00106               else if ((omod = lastmod(objndx(m), modname)) == OVOID) {
00107                      sprintf(errmsg, "undefined modifier \"%s\"", modname);
00108                      objerror(m, USER, errmsg);
00109               }
00110               if (rayshade(r, omod)) {
00111                      if (m->omod != OVOID)
00112                             objerror(m, USER, "inappropriate modifier");
00113                      return(1);
00114               }
00115        } else if (m->otype == PAT_BTEXT) {
00116               if (foreground)
00117                      scalecolor(r->pcol, m->oargs.farg[9]);
00118               else
00119                      scalecolor(r->pcol, m->oargs.farg[10]);
00120        } else { /* PAT_CTEXT */
00121               COLOR  cval;
00122               if (foreground)
00123                      setcolor(cval, m->oargs.farg[9],
00124                                    m->oargs.farg[10],
00125                                    m->oargs.farg[11]);
00126               else
00127                      setcolor(cval, m->oargs.farg[12],
00128                                    m->oargs.farg[13],
00129                                    m->oargs.farg[14]);
00130               multcolor(r->pcol, cval);
00131        }
00132        return(0);
00133 }
00134 
00135 
00136 static TLINE *
00137 tlalloc(                    /* allocate and assign text line */
00138        char  *s
00139 )
00140 {
00141        register int  siz;
00142        register TLINE  *tl;
00143 
00144        siz = strlen(s) + 1;
00145        if ((tl=(TLINE *)malloc(sizeof(TLINE)+siz)) == NULL ||
00146                      (tl->spc=(short *)malloc(siz*sizeof(short))) == NULL)
00147               error(SYSTEM, "out of memory in tlalloc");
00148        tl->next = NULL;
00149        strcpy(TLSTR(tl), s);
00150        return(tl);
00151 }
00152 
00153 
00154 static TEXT *
00155 gettext(                    /* get text structure for material */
00156        register OBJREC  *tm
00157 )
00158 {
00159 #define  R    (tm->oargs.farg+3)
00160 #define  D    (tm->oargs.farg+6)
00161        FVECT  DxR;
00162        double  d;
00163        FILE  *fp;
00164        char  linbuf[512];
00165        TEXT  *t;
00166        register int  i;
00167        register TLINE  *tlp;
00168        register char  *s;
00169 
00170        if ((t = (TEXT *)tm->os) != NULL)
00171               return(t);
00172                                           /* check arguments */
00173        if (tm->oargs.nsargs - tndx(tm) < 1 || tm->oargs.nfargs < sndx(tm))
00174               objerror(tm, USER, "bad # arguments");
00175        if ((t = (TEXT *)malloc(sizeof(TEXT))) == NULL)
00176               error(SYSTEM, "out of memory in gettext");
00177                                           /* compute vectors */
00178        fcross(DxR, D, R);
00179        fcross(t->right, DxR, D);
00180        d = DOT(t->right,t->right);
00181        if (d <= FTINY*FTINY*FTINY*FTINY)
00182               objerror(tm, USER, "illegal motion vector");
00183        d = DOT(D,D)/d;
00184        for (i = 0; i < 3; i++)
00185               t->right[i] *= d;
00186        fcross(t->down, R, DxR);
00187        d = DOT(R,R)/DOT(t->down,t->down);
00188        for (i = 0; i < 3; i++)
00189               t->down[i] *= d;
00190                                           /* get text */
00191        tlp = &t->tl;
00192        if (tm->oargs.nsargs - tndx(tm) > 1) {    /* single line */
00193               s = linbuf;
00194               for (i = tndx(tm)+1; i < tm->oargs.nsargs; i++) {
00195                      strcpy(s, tm->oargs.sarg[i]);
00196                      s += strlen(s);
00197                      *s++ = ' ';
00198               }
00199               *--s = '\0';
00200               tlp->next = tlalloc(linbuf);
00201               tlp = tlp->next;
00202        } else {                           /* text file */
00203               if ((s = getpath(tm->oargs.sarg[tndx(tm)],
00204                             getrlibpath(), R_OK)) == NULL) {
00205                      sprintf(errmsg, "cannot find text file \"%s\"",
00206                                    tm->oargs.sarg[tndx(tm)]);
00207                      error(USER, errmsg);
00208               }
00209               if ((fp = fopen(s, "r")) == NULL) {
00210                      sprintf(errmsg, "cannot open text file \"%s\"", s);
00211                      error(SYSTEM, errmsg);
00212               }
00213               while (fgets(linbuf, sizeof(linbuf), fp) != NULL) {
00214                      s = linbuf + strlen(linbuf) - 1;
00215                      if (*s == '\n')
00216                             *s = '\0';
00217                      tlp->next = tlalloc(linbuf);
00218                      tlp = tlp->next;
00219               }
00220               fclose(fp);
00221        }
00222        tlp->next = NULL;
00223                                           /* get the font */
00224        t->f = getfont(tm->oargs.sarg[fndx(tm)]);
00225                                           /* compute character spacing */
00226        i = sndx(tm);
00227        d = i < tm->oargs.nfargs ? tm->oargs.farg[i] : 0.0;
00228        i = d * 255.0;
00229        t->tl.width = 0;
00230        for (tlp = t->tl.next; tlp != NULL; tlp = tlp->next) {
00231               if (i < 0)
00232                      tlp->width = squeeztext(tlp->spc, TLSTR(tlp), t->f, -i);
00233               else if (i > 0)
00234                      tlp->width = proptext(tlp->spc, TLSTR(tlp), t->f, i, 3);
00235               else
00236                      tlp->width = uniftext(tlp->spc, TLSTR(tlp), t->f);
00237               if (tlp->width > t->tl.width)
00238                      t->tl.width = tlp->width;
00239        }
00240                                           /* we're done */
00241        tm->os = (char *)t;
00242        return(t);
00243 #undef  R
00244 #undef  D
00245 }
00246 
00247 
00248 extern void
00249 freetext(                   /* free text structures associated with m */
00250        OBJREC  *m
00251 )
00252 {
00253        register TEXT  *tp;
00254        register TLINE  *tlp;
00255 
00256        tp = (TEXT *)m->os;
00257        if (tp == NULL)
00258               return;
00259        while ((tlp = tp->tl.next) != NULL) {
00260               tp->tl.next = tlp->next;
00261               free((void *)tlp->spc);
00262               free((void *)tlp);
00263        }
00264        freefont(tp->f);     /* release font reference */
00265        free((void *)tp);
00266        m->os = NULL;
00267 }
00268 
00269 
00270 static int
00271 intext(                     /* check to see if p is in text glyph */
00272        FVECT  p,
00273        OBJREC  *m
00274 )
00275 {
00276        register TEXT  *tp;
00277        register TLINE  *tlp;
00278        FVECT  v;
00279        double  y, x;
00280        register int  i, h;
00281                             /* first, compute position in text */
00282        tp = gettext(m);
00283        v[0] = p[0] - m->oargs.farg[0];
00284        v[1] = p[1] - m->oargs.farg[1];
00285        v[2] = p[2] - m->oargs.farg[2];
00286        x = DOT(v, tp->right);
00287        i = sndx(m);
00288        if (i < m->oargs.nfargs)
00289               x *= tp->f->mwidth + 255.*fabs(m->oargs.farg[i]);
00290        else
00291               x *= 255.;
00292        h = x;
00293        i = y = DOT(v, tp->down);
00294        if (x < 0.0 || y < 0.0)
00295               return(0);
00296        x -= (double)h;
00297        y = ((i+1) - y)*255.;
00298                             /* find the line position */
00299        for (tlp = tp->tl.next; tlp != NULL; tlp = tlp->next)
00300               if (--i < 0)
00301                      break;
00302        if (tlp == NULL || h >= tlp->width)
00303               return(0);
00304        for (i = 0; (h -= tlp->spc[i]) >= 0; i++)
00305               if (h < 255 && inglyph(h+x, y,
00306                             tp->f->fg[TLSTR(tlp)[i]&0xff]))
00307                      return(1);
00308        return(0);
00309 }
00310 
00311 
00312 static int
00313 inglyph(             /* (x,y) within font glyph gl? */
00314        double  x,           /* real coordinates in range [0,255) */
00315        double  y,
00316        register GLYPH  *gl
00317 )
00318 {
00319        int  n, ncross;
00320        int  xlb, ylb;
00321        int  tv;
00322        register GORD  *p0, *p1;
00323 
00324        if (gl == NULL)
00325               return(0);
00326        xlb = x;
00327        ylb = y;
00328        if (gl->left > xlb || gl->right <= xlb || /* check extent */
00329                      gl->bottom > ylb || gl->top <= ylb)
00330               return(0);
00331        xlb = xlb<<1 | 1;           /* add 1/2 to test points... */
00332        ylb = ylb<<1 | 1;           /* ...so no equal comparisons */
00333        n = gl->nverts;                    /* get # of vertices */
00334        p0 = gvlist(gl) + 2*(n-1);  /* connect last to first */
00335        p1 = gvlist(gl);
00336        ncross = 0;
00337                                    /* positive x axis cross test */
00338        while (n--) {
00339               if ((p0[1]<<1 > ylb) ^ (p1[1]<<1 > ylb)) {
00340                      tv = (p0[0]<<1 > xlb) | ((p1[0]<<1 > xlb) << 1);
00341                      if (tv == 03)
00342                             ncross++;
00343                      else if (tv)
00344                             ncross += (p1[1] > p0[1]) ^
00345                                           ((p0[1]-y)*(p1[0]-x) >
00346                                           (p0[0]-x)*(p1[1]-y));
00347               }
00348               p0 = p1;
00349               p1 += 2;
00350        }
00351        return(ncross & 01);
00352 }