| 1 | – | /* Copyright (c) 1991 Regents of the University of California */ | 
| 2 | – |  | 
| 1 |  | #ifndef lint | 
| 2 | < | static char SCCSid[] = "$SunId$ LBL"; | 
| 2 | > | static const char       RCSid[] = "$Id$"; | 
| 3 |  | #endif | 
| 6 | – |  | 
| 4 |  | /* | 
| 5 |  | *  text.c - functions for text patterns and mixtures. | 
| 9 | – | * | 
| 10 | – | *     11/12/86 | 
| 6 |  | */ | 
| 7 |  |  | 
| 8 | < | #include  "ray.h" | 
| 8 | > | #include "copyright.h" | 
| 9 |  |  | 
| 10 | + | #include  "ray.h" | 
| 11 | + | #include  "paths.h" | 
| 12 |  | #include  "otypes.h" | 
| 13 | < |  | 
| 13 | > | #include  "rtotypes.h" | 
| 14 |  | #include  "font.h" | 
| 15 |  |  | 
| 16 |  | /* | 
| 42 |  | *              [spacing] | 
| 43 |  | * | 
| 44 |  | *  Colortext is identical, except colors are given rather than | 
| 45 | < | *  brightnesses.  Mixtext has foreground and background modifiers: | 
| 45 | > | *  brightnesses. | 
| 46 |  | * | 
| 47 | + | *  Mixtext has foreground and background modifiers: | 
| 48 | + | * | 
| 49 |  | *      modifier mixtext id | 
| 50 |  | *      4+ foremod backmod fontfile text.. | 
| 51 |  | *      0 | 
| 76 |  | TLINE  tl;                      /* line list */ | 
| 77 |  | }  TEXT; | 
| 78 |  |  | 
| 79 | < | extern char  *libpath; | 
| 79 | > | static TLINE * tlalloc(char *s); | 
| 80 | > | static TEXT * gettext(OBJREC *tm); | 
| 81 | > | static int intext(FVECT p, OBJREC *m); | 
| 82 | > | static int inglyph(double x, double y, GLYPH *gl); | 
| 83 |  |  | 
| 82 | – | extern char  *fgetword(); | 
| 84 |  |  | 
| 85 | < | TEXT  *gettext(); | 
| 86 | < |  | 
| 87 | < | TLINE  *tlalloc(); | 
| 88 | < |  | 
| 89 | < |  | 
| 89 | < | text(m, r) | 
| 90 | < | register OBJREC  *m; | 
| 91 | < | RAY  *r; | 
| 85 | > | int | 
| 86 | > | do_text( | 
| 87 | > | OBJREC  *m, | 
| 88 | > | RAY  *r | 
| 89 | > | ) | 
| 90 |  | { | 
| 91 |  | FVECT  v; | 
| 92 |  | int  foreground; | 
| 103 |  | char  *modname = m->oargs.sarg[foreground ? 0 : 1]; | 
| 104 |  | if (!strcmp(modname, VOIDID)) | 
| 105 |  | omod = OVOID; | 
| 106 | < | else if ((omod = modifier(modname)) == OVOID) { | 
| 106 | > | else if ((omod = lastmod(objndx(m), modname)) == OVOID) { | 
| 107 |  | sprintf(errmsg, "undefined modifier \"%s\"", modname); | 
| 108 |  | objerror(m, USER, errmsg); | 
| 109 |  | } | 
| 110 | < | raytexture(r, omod); | 
| 110 | > | if (rayshade(r, omod)) { | 
| 111 | > | if (m->omod != OVOID) | 
| 112 | > | objerror(m, USER, "inappropriate modifier"); | 
| 113 | > | return(1); | 
| 114 | > | } | 
| 115 |  | } else if (m->otype == PAT_BTEXT) { | 
| 116 | < | if (foreground) | 
| 117 | < | scalecolor(r->pcol, m->oargs.farg[9]); | 
| 118 | < | else | 
| 119 | < | scalecolor(r->pcol, m->oargs.farg[10]); | 
| 116 | > | if (foreground) { | 
| 117 | > | scalescolor(r->pcol, m->oargs.farg[9]); | 
| 118 | > | } else { | 
| 119 | > | scalescolor(r->pcol, m->oargs.farg[10]); | 
| 120 | > | } | 
| 121 |  | } else { /* PAT_CTEXT */ | 
| 122 | < | COLOR  cval; | 
| 122 | > | SCOLOR  scval; | 
| 123 |  | if (foreground) | 
| 124 | < | setcolor(cval, m->oargs.farg[9], | 
| 124 | > | setscolor(scval, m->oargs.farg[9], | 
| 125 |  | m->oargs.farg[10], | 
| 126 |  | m->oargs.farg[11]); | 
| 127 |  | else | 
| 128 | < | setcolor(cval, m->oargs.farg[12], | 
| 128 | > | setscolor(scval, m->oargs.farg[12], | 
| 129 |  | m->oargs.farg[13], | 
| 130 |  | m->oargs.farg[14]); | 
| 131 | < | multcolor(r->pcol, cval); | 
| 131 | > | smultscolor(r->pcol, scval); | 
| 132 |  | } | 
| 133 | + | return(0); | 
| 134 |  | } | 
| 135 |  |  | 
| 136 |  |  | 
| 137 | < | TLINE * | 
| 138 | < | tlalloc(s)                      /* allocate and assign text line */ | 
| 139 | < | char  *s; | 
| 137 | > | static TLINE * | 
| 138 | > | tlalloc(                        /* allocate and assign text line */ | 
| 139 | > | char  *s | 
| 140 | > | ) | 
| 141 |  | { | 
| 142 | < | extern char  *strcpy(); | 
| 143 | < | register int  siz; | 
| 139 | < | register TLINE  *tl; | 
| 142 | > | int  siz; | 
| 143 | > | TLINE  *tl; | 
| 144 |  |  | 
| 145 |  | siz = strlen(s) + 1; | 
| 146 |  | if ((tl=(TLINE *)malloc(sizeof(TLINE)+siz)) == NULL || | 
| 147 |  | (tl->spc=(short *)malloc(siz*sizeof(short))) == NULL) | 
| 148 |  | error(SYSTEM, "out of memory in tlalloc"); | 
| 145 | – | tl->spc = NULL; | 
| 149 |  | tl->next = NULL; | 
| 150 |  | strcpy(TLSTR(tl), s); | 
| 151 |  | return(tl); | 
| 152 |  | } | 
| 153 |  |  | 
| 154 |  |  | 
| 155 | < | TEXT * | 
| 156 | < | gettext(tm)                     /* get text structure for material */ | 
| 157 | < | register OBJREC  *tm; | 
| 155 | > | static TEXT * | 
| 156 | > | gettext(                        /* get text structure for material */ | 
| 157 | > | OBJREC  *tm | 
| 158 | > | ) | 
| 159 |  | { | 
| 160 |  | #define  R      (tm->oargs.farg+3) | 
| 161 |  | #define  D      (tm->oargs.farg+6) | 
| 158 | – | extern char  *strcpy(), *fgets(); | 
| 162 |  | FVECT  DxR; | 
| 163 |  | double  d; | 
| 164 |  | FILE  *fp; | 
| 165 |  | char  linbuf[512]; | 
| 166 |  | TEXT  *t; | 
| 167 | < | register int  i; | 
| 168 | < | register TLINE  *tlp; | 
| 169 | < | register char  *s; | 
| 167 | > | int  i; | 
| 168 | > | TLINE  *tlp; | 
| 169 | > | char  *s; | 
| 170 |  |  | 
| 171 |  | if ((t = (TEXT *)tm->os) != NULL) | 
| 172 |  | return(t); | 
| 174 |  | if (tm->oargs.nsargs - tndx(tm) < 1 || tm->oargs.nfargs < sndx(tm)) | 
| 175 |  | objerror(tm, USER, "bad # arguments"); | 
| 176 |  | if ((t = (TEXT *)malloc(sizeof(TEXT))) == NULL) | 
| 177 | < | goto memerr; | 
| 177 | > | error(SYSTEM, "out of memory in gettext"); | 
| 178 |  | /* compute vectors */ | 
| 179 |  | fcross(DxR, D, R); | 
| 180 |  | fcross(t->right, DxR, D); | 
| 181 | < | d = DOT(D,D)/DOT(t->right,t->right); | 
| 181 | > | d = DOT(t->right,t->right); | 
| 182 | > | if (d <= FTINY*FTINY*FTINY*FTINY) | 
| 183 | > | objerror(tm, USER, "illegal motion vector"); | 
| 184 | > | d = DOT(D,D)/d; | 
| 185 |  | for (i = 0; i < 3; i++) | 
| 186 |  | t->right[i] *= d; | 
| 187 |  | fcross(t->down, R, DxR); | 
| 202 |  | tlp = tlp->next; | 
| 203 |  | } else {                                /* text file */ | 
| 204 |  | if ((s = getpath(tm->oargs.sarg[tndx(tm)], | 
| 205 | < | libpath, R_OK)) == NULL) { | 
| 205 | > | getrlibpath(), R_OK)) == NULL) { | 
| 206 |  | sprintf(errmsg, "cannot find text file \"%s\"", | 
| 207 |  | tm->oargs.sarg[tndx(tm)]); | 
| 208 | < | error(USER, errmsg); | 
| 208 | > | error(SYSTEM, errmsg); | 
| 209 |  | } | 
| 210 |  | if ((fp = fopen(s, "r")) == NULL) { | 
| 211 |  | sprintf(errmsg, "cannot open text file \"%s\"", s); | 
| 223 |  | tlp->next = NULL; | 
| 224 |  | /* get the font */ | 
| 225 |  | t->f = getfont(tm->oargs.sarg[fndx(tm)]); | 
| 226 | + | if (!t->f) | 
| 227 | + | objerror(tm, USER, "font load error"); | 
| 228 |  | /* compute character spacing */ | 
| 229 |  | i = sndx(tm); | 
| 230 |  | d = i < tm->oargs.nfargs ? tm->oargs.farg[i] : 0.0; | 
| 231 | < | i = d * 256.0; | 
| 231 | > | i = d * 255.0; | 
| 232 | > | t->tl.width = 0; | 
| 233 |  | for (tlp = t->tl.next; tlp != NULL; tlp = tlp->next) { | 
| 225 | – | if ((tlp->spc = (short *)malloc( | 
| 226 | – | (strlen(TLSTR(tlp))+1)*sizeof(short))) == NULL) | 
| 227 | – | goto memerr; | 
| 234 |  | if (i < 0) | 
| 235 |  | tlp->width = squeeztext(tlp->spc, TLSTR(tlp), t->f, -i); | 
| 236 |  | else if (i > 0) | 
| 237 |  | tlp->width = proptext(tlp->spc, TLSTR(tlp), t->f, i, 3); | 
| 238 |  | else | 
| 239 |  | tlp->width = uniftext(tlp->spc, TLSTR(tlp), t->f); | 
| 240 | + | if (tlp->width > t->tl.width) | 
| 241 | + | t->tl.width = tlp->width; | 
| 242 |  | } | 
| 243 |  | /* we're done */ | 
| 244 |  | tm->os = (char *)t; | 
| 245 |  | return(t); | 
| 238 | – | memerr: | 
| 239 | – | error(SYSTEM, "out of memory in gettext"); | 
| 246 |  | #undef  R | 
| 247 |  | #undef  D | 
| 248 |  | } | 
| 249 |  |  | 
| 250 |  |  | 
| 251 | < | freetext(m)                     /* free text structures associated with m */ | 
| 252 | < | OBJREC  *m; | 
| 251 | > | void | 
| 252 | > | freetext(                       /* free text structures associated with m */ | 
| 253 | > | OBJREC  *m | 
| 254 | > | ) | 
| 255 |  | { | 
| 256 | < | register TEXT  *tp; | 
| 257 | < | register TLINE  *tlp; | 
| 256 | > | TEXT  *tp; | 
| 257 | > | TLINE  *tlp; | 
| 258 |  |  | 
| 259 |  | tp = (TEXT *)m->os; | 
| 260 |  | if (tp == NULL) | 
| 261 |  | return; | 
| 262 | < | for (tlp = tp->tl.next; tlp != NULL; tlp = tlp->next) { | 
| 263 | < | free((char *)tlp->spc); | 
| 264 | < | free((char *)tlp); | 
| 262 | > | while ((tlp = tp->tl.next) != NULL) { | 
| 263 | > | tp->tl.next = tlp->next; | 
| 264 | > | free((void *)tlp->spc); | 
| 265 | > | free((void *)tlp); | 
| 266 |  | } | 
| 267 | < | free((char *)tp); | 
| 267 | > | freefont(tp->f);        /* release font reference */ | 
| 268 | > | free((void *)tp); | 
| 269 |  | m->os = NULL; | 
| 270 |  | } | 
| 271 |  |  | 
| 272 |  |  | 
| 273 | < | intext(p, m)                    /* check to see if p is in text glyph */ | 
| 274 | < | FVECT  p; | 
| 275 | < | OBJREC  *m; | 
| 273 | > | static int | 
| 274 | > | intext(                 /* check to see if p is in text glyph */ | 
| 275 | > | FVECT  p, | 
| 276 | > | OBJREC  *m | 
| 277 | > | ) | 
| 278 |  | { | 
| 279 | < | register TEXT  *tp; | 
| 280 | < | register TLINE  *tlp; | 
| 279 | > | TEXT  *tp; | 
| 280 | > | TLINE  *tlp; | 
| 281 |  | FVECT  v; | 
| 282 |  | double  y, x; | 
| 283 | < | register int  i, h; | 
| 283 | > | int  i, h; | 
| 284 |  | /* first, compute position in text */ | 
| 285 |  | tp = gettext(m); | 
| 286 |  | v[0] = p[0] - m->oargs.farg[0]; | 
| 287 |  | v[1] = p[1] - m->oargs.farg[1]; | 
| 288 |  | v[2] = p[2] - m->oargs.farg[2]; | 
| 289 | < | h = x = DOT(v, tp->right)*256.; | 
| 289 | > | x = DOT(v, tp->right); | 
| 290 | > | i = sndx(m); | 
| 291 | > | if (i < m->oargs.nfargs) | 
| 292 | > | x *= tp->f->mwidth + 255.*fabs(m->oargs.farg[i]); | 
| 293 | > | else | 
| 294 | > | x *= 255.; | 
| 295 | > | h = x; | 
| 296 |  | i = y = DOT(v, tp->down); | 
| 297 | < | if (x < 0.0 || y < 0.0) | 
| 297 | > | if ((x < 0.0) | (y < 0.0)) | 
| 298 |  | return(0); | 
| 299 |  | x -= (double)h; | 
| 300 | < | y = ((i+1) - y)*256.; | 
| 300 | > | y = ((i+1) - y)*255.; | 
| 301 |  | /* find the line position */ | 
| 302 |  | for (tlp = tp->tl.next; tlp != NULL; tlp = tlp->next) | 
| 303 |  | if (--i < 0) | 
| 305 |  | if (tlp == NULL || h >= tlp->width) | 
| 306 |  | return(0); | 
| 307 |  | for (i = 0; (h -= tlp->spc[i]) >= 0; i++) | 
| 308 | < | if (h < 256 && inglyph(h+x, y, | 
| 308 | > | if (h < 255 && inglyph(h+x, y, | 
| 309 |  | tp->f->fg[TLSTR(tlp)[i]&0xff])) | 
| 310 |  | return(1); | 
| 311 |  | return(0); | 
| 312 |  | } | 
| 313 |  |  | 
| 314 |  |  | 
| 315 | < | inglyph(x, y, gl)               /* (x,y) within font glyph gl? */ | 
| 316 | < | double  x, y; | 
| 317 | < | register GLYPH  *gl; | 
| 315 | > | static int | 
| 316 | > | inglyph(                /* (x,y) within font glyph gl? */ | 
| 317 | > | double  x,              /* real coordinates in range [0,255) */ | 
| 318 | > | double  y, | 
| 319 | > | GLYPH  *gl | 
| 320 | > | ) | 
| 321 |  | { | 
| 322 |  | int  n, ncross; | 
| 323 | < | int  xtc, ytc; | 
| 324 | < | register GORD  *p0, *p1; | 
| 323 | > | int  xlb, ylb; | 
| 324 | > | int  tv; | 
| 325 | > | GORD  *p0, *p1; | 
| 326 |  |  | 
| 327 |  | if (gl == NULL) | 
| 328 |  | return(0); | 
| 329 | < | xtc = x + 0.5;                  /* compute test coordinates */ | 
| 330 | < | ytc = y + 0.5; | 
| 331 | < | if (gl->left > xtc || gl->right < xtc || | 
| 332 | < | gl->bottom > ytc || gl->top < ytc) | 
| 333 | < | return(0);      /* outside extent */ | 
| 329 | > | xlb = x; | 
| 330 | > | ylb = y; | 
| 331 | > | if ((gl->left > xlb) | (gl->right <= xlb) |     /* check extent */ | 
| 332 | > | (gl->bottom > ylb) | (gl->top <= ylb)) | 
| 333 | > | return(0); | 
| 334 | > | xlb = xlb<<1 | 1;               /* add 1/2 to test points... */ | 
| 335 | > | ylb = ylb<<1 | 1;               /* ...so no equal comparisons */ | 
| 336 |  | n = gl->nverts;                 /* get # of vertices */ | 
| 337 |  | p0 = gvlist(gl) + 2*(n-1);      /* connect last to first */ | 
| 338 |  | p1 = gvlist(gl); | 
| 339 |  | ncross = 0; | 
| 340 |  | /* positive x axis cross test */ | 
| 341 |  | while (n--) { | 
| 342 | < | if ((p0[1] > ytc) ^ (p1[1] > ytc)) | 
| 343 | < | if (p0[0] > xtc && p1[0] > xtc) | 
| 342 | > | if ((p0[1]<<1 > ylb) ^ (p1[1]<<1 > ylb)) { | 
| 343 | > | tv = (p0[0]<<1 > xlb) | ((p1[0]<<1 > xlb) << 1); | 
| 344 | > | if (tv == 03) | 
| 345 |  | ncross++; | 
| 346 | < | else if (p0[0] > xtc || p1[0] > xtc) | 
| 346 | > | else if (tv) | 
| 347 |  | ncross += (p1[1] > p0[1]) ^ | 
| 348 |  | ((p0[1]-y)*(p1[0]-x) > | 
| 349 |  | (p0[0]-x)*(p1[1]-y)); | 
| 350 | + | } | 
| 351 |  | p0 = p1; | 
| 352 |  | p1 += 2; | 
| 353 |  | } |