| 1 | greg | 1.1 | #ifndef lint | 
| 2 | greg | 2.103 | static const char       RCSid[] = "$Id: rtrace.c,v 2.102 2021/04/16 16:31:35 greg Exp $"; | 
| 3 | greg | 1.1 | #endif | 
| 4 |  |  | /* | 
| 5 |  |  | *  rtrace.c - program and variables for individual ray tracing. | 
| 6 | greg | 2.27 | */ | 
| 7 |  |  |  | 
| 8 | greg | 2.28 | #include "copyright.h" | 
| 9 | greg | 1.1 |  | 
| 10 |  |  | /* | 
| 11 |  |  | *  Input is in the form: | 
| 12 |  |  | * | 
| 13 |  |  | *      xorg    yorg    zorg    xdir    ydir    zdir | 
| 14 |  |  | * | 
| 15 |  |  | *  The direction need not be normalized.  Output is flexible. | 
| 16 | greg | 1.7 | *  If the direction vector is (0,0,0), then the output is flushed. | 
| 17 | greg | 1.1 | *  All values default to ascii representation of real | 
| 18 |  |  | *  numbers.  Binary representations can be selected | 
| 19 |  |  | *  with '-ff' for float or '-fd' for double.  By default, | 
| 20 | greg | 1.13 | *  radiance is computed.  The '-i' or '-I' options indicate that | 
| 21 | greg | 1.1 | *  irradiance values are desired. | 
| 22 |  |  | */ | 
| 23 | greg | 2.32 |  | 
| 24 |  |  | #include  <time.h> | 
| 25 | greg | 1.1 |  | 
| 26 | schorsch | 2.30 | #include  "platform.h" | 
| 27 | greg | 1.1 | #include  "ray.h" | 
| 28 | schorsch | 2.37 | #include  "ambient.h" | 
| 29 |  |  | #include  "source.h" | 
| 30 | greg | 1.1 | #include  "otypes.h" | 
| 31 | greg | 2.72 | #include  "otspecial.h" | 
| 32 | greg | 2.6 | #include  "resolu.h" | 
| 33 | schorsch | 2.49 | #include  "random.h" | 
| 34 | greg | 2.6 |  | 
| 35 | greg | 2.57 | extern int  inform;                     /* input format */ | 
| 36 |  |  | extern int  outform;                    /* output format */ | 
| 37 |  |  | extern char  *outvals;                  /* output values */ | 
| 38 | greg | 2.27 |  | 
| 39 | greg | 2.57 | extern int  imm_irrad;                  /* compute immediate irradiance? */ | 
| 40 |  |  | extern int  lim_dist;                   /* limit distance? */ | 
| 41 | greg | 1.14 |  | 
| 42 | greg | 2.57 | extern char  *tralist[];                /* list of modifers to trace (or no) */ | 
| 43 |  |  | extern int  traincl;                    /* include == 1, exclude == 0 */ | 
| 44 | greg | 1.13 |  | 
| 45 | greg | 2.57 | extern int  hresolu;                    /* horizontal resolution */ | 
| 46 |  |  | extern int  vresolu;                    /* vertical resolution */ | 
| 47 | greg | 1.1 |  | 
| 48 | greg | 2.94 | int  castonly = 0;                      /* only doing ray-casting? */ | 
| 49 | greg | 2.55 |  | 
| 50 | greg | 2.46 | #ifndef  MAXTSET | 
| 51 | greg | 2.55 | #define  MAXTSET        8191            /* maximum number in trace set */ | 
| 52 | greg | 2.46 | #endif | 
| 53 | greg | 2.15 | OBJECT  traset[MAXTSET+1]={0};          /* trace include/exclude set */ | 
| 54 |  |  |  | 
| 55 | greg | 2.102 | static int  Tflag = 0;                  /* source tracing enabled? */ | 
| 56 |  |  |  | 
| 57 | greg | 1.1 | static RAY  thisray;                    /* for our convenience */ | 
| 58 |  |  |  | 
| 59 | greg | 2.89 | static FILE  *inpfp = NULL;             /* input stream pointer */ | 
| 60 |  |  |  | 
| 61 |  |  | static FVECT    *inp_queue = NULL;      /* ray input queue if flushing */ | 
| 62 |  |  | static int      inp_qpos = 0;           /* next ray to return */ | 
| 63 |  |  | static int      inp_qend = 0;           /* number of rays in this work group */ | 
| 64 |  |  |  | 
| 65 | greg | 2.65 | typedef void putf_t(RREAL *v, int n); | 
| 66 | greg | 2.80 | static putf_t puta, putd, putf, putrgbe; | 
| 67 | greg | 1.1 |  | 
| 68 | schorsch | 2.37 | typedef void oputf_t(RAY *r); | 
| 69 | greg | 2.51 | static oputf_t  oputo, oputd, oputv, oputV, oputl, oputL, oputc, oputp, | 
| 70 | greg | 2.73 | oputr, oputR, oputx, oputX, oputn, oputN, oputs, | 
| 71 |  |  | oputw, oputW, oputm, oputM, oputtilde; | 
| 72 | schorsch | 2.37 |  | 
| 73 | greg | 2.92 | extern void tranotify(OBJECT obj); | 
| 74 |  |  | static int is_fifo(FILE *fp); | 
| 75 | schorsch | 2.37 | static void bogusray(void); | 
| 76 | greg | 2.59 | static void raycast(RAY *r); | 
| 77 |  |  | static void rayirrad(RAY *r); | 
| 78 |  |  | static void rtcompute(FVECT org, FVECT dir, double dmax); | 
| 79 | greg | 2.57 | static int printvals(RAY *r); | 
| 80 |  |  | static int getvec(FVECT vec, int fmt, FILE *fp); | 
| 81 | greg | 2.89 | static int iszerovec(const FVECT vec); | 
| 82 |  |  | static double nextray(FVECT org, FVECT dir); | 
| 83 | greg | 2.57 | static void tabin(RAY *r); | 
| 84 |  |  | static void ourtrace(RAY *r); | 
| 85 | greg | 1.1 |  | 
| 86 | greg | 2.73 | static oputf_t *ray_out[32], *every_out[32]; | 
| 87 | schorsch | 2.37 | static putf_t *putreal; | 
| 88 | greg | 2.27 |  | 
| 89 | greg | 1.1 |  | 
| 90 | greg | 2.27 | void | 
| 91 | schorsch | 2.37 | quit(                   /* quit program */ | 
| 92 |  |  | int  code | 
| 93 |  |  | ) | 
| 94 | greg | 1.1 | { | 
| 95 | greg | 2.57 | if (ray_pnprocs > 0)    /* close children if any */ | 
| 96 |  |  | ray_pclose(0); | 
| 97 | greg | 2.99 | else if (ray_pnprocs < 0) | 
| 98 |  |  | _exit(code);    /* avoid flush() in child */ | 
| 99 | greg | 2.57 | #ifndef  NON_POSIX | 
| 100 | greg | 2.99 | else { | 
| 101 | greg | 2.58 | headclean();    /* delete header file */ | 
| 102 |  |  | pfclean();      /* clean up persist files */ | 
| 103 |  |  | } | 
| 104 | greg | 2.11 | #endif | 
| 105 | greg | 1.1 | exit(code); | 
| 106 |  |  | } | 
| 107 |  |  |  | 
| 108 |  |  |  | 
| 109 | greg | 2.57 | char * | 
| 110 | schorsch | 2.37 | formstr(                                /* return format identifier */ | 
| 111 |  |  | int  f | 
| 112 |  |  | ) | 
| 113 | greg | 2.6 | { | 
| 114 |  |  | switch (f) { | 
| 115 |  |  | case 'a': return("ascii"); | 
| 116 |  |  | case 'f': return("float"); | 
| 117 |  |  | case 'd': return("double"); | 
| 118 |  |  | case 'c': return(COLRFMT); | 
| 119 |  |  | } | 
| 120 |  |  | return("unknown"); | 
| 121 |  |  | } | 
| 122 |  |  |  | 
| 123 |  |  |  | 
| 124 | greg | 2.102 | static void | 
| 125 |  |  | trace_sources(void)                     /* trace rays to light sources, also */ | 
| 126 |  |  | { | 
| 127 |  |  | int     sn; | 
| 128 |  |  |  | 
| 129 |  |  | for (sn = 0; sn < nsources; sn++) | 
| 130 |  |  | source[sn].sflags |= SFOLLOW; | 
| 131 |  |  | } | 
| 132 |  |  |  | 
| 133 |  |  |  | 
| 134 | greg | 2.92 | void | 
| 135 | schorsch | 2.37 | rtrace(                         /* trace rays from file */ | 
| 136 | greg | 2.59 | char  *fname, | 
| 137 |  |  | int  nproc | 
| 138 | schorsch | 2.37 | ) | 
| 139 | greg | 1.1 | { | 
| 140 | greg | 2.45 | unsigned long  vcount = (hresolu > 1) ? (unsigned long)hresolu*vresolu | 
| 141 | greg | 2.66 | : (unsigned long)vresolu; | 
| 142 | greg | 2.85 | long  nextflush = (!vresolu | (hresolu <= 1)) * hresolu; | 
| 143 | greg | 2.79 | int  something2flush = 0; | 
| 144 | greg | 1.1 | FILE  *fp; | 
| 145 | gregl | 2.25 | double  d; | 
| 146 | greg | 1.2 | FVECT  orig, direc; | 
| 147 | greg | 1.1 | /* set up input */ | 
| 148 |  |  | if (fname == NULL) | 
| 149 | greg | 2.89 | inpfp = stdin; | 
| 150 |  |  | else if ((inpfp = fopen(fname, "r")) == NULL) { | 
| 151 | greg | 1.1 | sprintf(errmsg, "cannot open input file \"%s\"", fname); | 
| 152 |  |  | error(SYSTEM, errmsg); | 
| 153 |  |  | } | 
| 154 | greg | 2.89 | #ifdef getc_unlocked | 
| 155 |  |  | flockfile(inpfp);               /* avoid lock/unlock overhead */ | 
| 156 |  |  | flockfile(stdout); | 
| 157 |  |  | #endif | 
| 158 | greg | 2.8 | if (inform != 'a') | 
| 159 | greg | 2.89 | SET_FILE_BINARY(inpfp); | 
| 160 | greg | 1.1 | /* set up output */ | 
| 161 | greg | 2.94 | if (castonly || every_out[0] != NULL) | 
| 162 | greg | 2.59 | nproc = 1;              /* don't bother multiprocessing */ | 
| 163 | greg | 2.102 | if (Tflag && every_out[0] != NULL) | 
| 164 |  |  | trace_sources();        /* asking to trace light sources */ | 
| 165 | greg | 2.79 | if ((nextflush > 0) & (nproc > nextflush)) { | 
| 166 |  |  | error(WARNING, "reducing number of processes to match flush interval"); | 
| 167 |  |  | nproc = nextflush; | 
| 168 |  |  | } | 
| 169 | greg | 2.59 | if (nproc > 1) {                /* start multiprocessing */ | 
| 170 |  |  | ray_popen(nproc); | 
| 171 | greg | 2.58 | ray_fifo_out = printvals; | 
| 172 | greg | 2.59 | } | 
| 173 | greg | 2.12 | if (hresolu > 0) { | 
| 174 |  |  | if (vresolu > 0) | 
| 175 |  |  | fprtresolu(hresolu, vresolu, stdout); | 
| 176 | greg | 2.78 | else | 
| 177 |  |  | fflush(stdout); | 
| 178 | greg | 2.12 | } | 
| 179 | greg | 2.89 | /* process input rays */ | 
| 180 |  |  | while ((d = nextray(orig, direc)) >= 0.0) { | 
| 181 | greg | 2.87 | if (d == 0.0) {                         /* flush request? */ | 
| 182 | greg | 2.85 | if (something2flush) { | 
| 183 | greg | 2.74 | if (ray_pnprocs > 1 && ray_fifo_flush() < 0) | 
| 184 | greg | 2.71 | error(USER, "child(ren) died"); | 
| 185 | greg | 2.87 | bogusray(); | 
| 186 | gregl | 2.24 | fflush(stdout); | 
| 187 | greg | 2.86 | nextflush = (!vresolu | (hresolu <= 1)) * hresolu; | 
| 188 | greg | 2.79 | something2flush = 0; | 
| 189 | greg | 2.87 | } else | 
| 190 |  |  | bogusray(); | 
| 191 | greg | 2.57 | } else {                                /* compute and print */ | 
| 192 | greg | 2.59 | rtcompute(orig, direc, lim_dist ? d : 0.0); | 
| 193 | greg | 2.89 | if (!--nextflush) {             /* flush if time */ | 
| 194 | greg | 2.74 | if (ray_pnprocs > 1 && ray_fifo_flush() < 0) | 
| 195 | greg | 2.71 | error(USER, "child(ren) died"); | 
| 196 | gregl | 2.24 | fflush(stdout); | 
| 197 |  |  | nextflush = hresolu; | 
| 198 | greg | 2.78 | } else | 
| 199 | greg | 2.79 | something2flush = 1; | 
| 200 | greg | 1.1 | } | 
| 201 |  |  | if (ferror(stdout)) | 
| 202 |  |  | error(SYSTEM, "write error"); | 
| 203 | greg | 2.45 | if (vcount && !--vcount)                /* check for end */ | 
| 204 | greg | 1.1 | break; | 
| 205 |  |  | } | 
| 206 | greg | 2.74 | if (ray_pnprocs > 1) {                          /* clean up children */ | 
| 207 | greg | 2.59 | if (ray_fifo_flush() < 0) | 
| 208 |  |  | error(USER, "unable to complete processing"); | 
| 209 |  |  | ray_pclose(0); | 
| 210 |  |  | } | 
| 211 | greg | 2.89 | if (vcount) | 
| 212 |  |  | error(WARNING, "unexpected EOF on input"); | 
| 213 | greg | 2.50 | if (fflush(stdout) < 0) | 
| 214 |  |  | error(SYSTEM, "write error"); | 
| 215 | greg | 2.89 | if (fname != NULL) { | 
| 216 |  |  | fclose(inpfp); | 
| 217 |  |  | inpfp = NULL; | 
| 218 |  |  | } | 
| 219 |  |  | nextray(NULL, NULL); | 
| 220 | greg | 1.1 | } | 
| 221 |  |  |  | 
| 222 |  |  |  | 
| 223 | greg | 2.91 | int | 
| 224 |  |  | setrtoutput(void)                       /* set up output tables, return #comp */ | 
| 225 | greg | 1.1 | { | 
| 226 | greg | 2.91 | char  *vs = outvals; | 
| 227 | greg | 2.56 | oputf_t **table = ray_out; | 
| 228 | greg | 2.91 | int  ncomp = 0; | 
| 229 |  |  |  | 
| 230 |  |  | if (!*vs) | 
| 231 |  |  | error(USER, "empty output specification"); | 
| 232 | greg | 1.1 |  | 
| 233 | greg | 2.103 | switch (outform) {      /* make sure (*putreal)() calls someone! */ | 
| 234 |  |  | case 'a': putreal = puta; break; | 
| 235 |  |  | case 'f': putreal = putf; break; | 
| 236 |  |  | case 'd': putreal = putd; break; | 
| 237 |  |  | case 'c': | 
| 238 |  |  | if (outvals[1] || !strchr("vrx", outvals[0])) | 
| 239 |  |  | error(USER, "color format only with -ov, -or, -ox"); | 
| 240 |  |  | putreal = putrgbe; break; | 
| 241 |  |  | default: | 
| 242 |  |  | error(CONSISTENCY, "botched output format"); | 
| 243 |  |  | } | 
| 244 | greg | 2.94 | castonly = 1;                   /* sets castonly as side-effect */ | 
| 245 | greg | 2.91 | do | 
| 246 |  |  | switch (*vs) { | 
| 247 | greg | 2.40 | case 'T':                               /* trace sources */ | 
| 248 | greg | 2.102 | Tflag++; | 
| 249 | greg | 2.40 | /* fall through */ | 
| 250 | greg | 1.1 | case 't':                               /* trace */ | 
| 251 | greg | 2.91 | if (!vs[1]) break; | 
| 252 | greg | 1.1 | *table = NULL; | 
| 253 |  |  | table = every_out; | 
| 254 |  |  | trace = ourtrace; | 
| 255 | greg | 1.11 | castonly = 0; | 
| 256 | greg | 1.1 | break; | 
| 257 |  |  | case 'o':                               /* origin */ | 
| 258 |  |  | *table++ = oputo; | 
| 259 | greg | 2.91 | ncomp += 3; | 
| 260 | greg | 1.1 | break; | 
| 261 |  |  | case 'd':                               /* direction */ | 
| 262 |  |  | *table++ = oputd; | 
| 263 | greg | 2.91 | ncomp += 3; | 
| 264 | greg | 1.1 | break; | 
| 265 | greg | 2.73 | case 'r':                               /* reflected contrib. */ | 
| 266 |  |  | *table++ = oputr; | 
| 267 | greg | 2.91 | ncomp += 3; | 
| 268 | greg | 2.73 | castonly = 0; | 
| 269 |  |  | break; | 
| 270 |  |  | case 'R':                               /* reflected distance */ | 
| 271 |  |  | *table++ = oputR; | 
| 272 | greg | 2.91 | ncomp++; | 
| 273 | greg | 2.73 | castonly = 0; | 
| 274 |  |  | break; | 
| 275 |  |  | case 'x':                               /* xmit contrib. */ | 
| 276 |  |  | *table++ = oputx; | 
| 277 | greg | 2.91 | ncomp += 3; | 
| 278 | greg | 2.73 | castonly = 0; | 
| 279 |  |  | break; | 
| 280 |  |  | case 'X':                               /* xmit distance */ | 
| 281 |  |  | *table++ = oputX; | 
| 282 | greg | 2.91 | ncomp++; | 
| 283 | greg | 2.73 | castonly = 0; | 
| 284 |  |  | break; | 
| 285 | greg | 1.1 | case 'v':                               /* value */ | 
| 286 |  |  | *table++ = oputv; | 
| 287 | greg | 2.91 | ncomp += 3; | 
| 288 | greg | 1.11 | castonly = 0; | 
| 289 | greg | 1.1 | break; | 
| 290 | greg | 2.51 | case 'V':                               /* contribution */ | 
| 291 |  |  | *table++ = oputV; | 
| 292 | greg | 2.91 | ncomp += 3; | 
| 293 | greg | 2.94 | castonly = 0; | 
| 294 | greg | 2.51 | if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0)) | 
| 295 |  |  | error(WARNING, | 
| 296 |  |  | "-otV accuracy depends on -aa 0 -as 0"); | 
| 297 |  |  | break; | 
| 298 | greg | 2.5 | case 'l':                               /* effective distance */ | 
| 299 | greg | 1.1 | *table++ = oputl; | 
| 300 | greg | 2.91 | ncomp++; | 
| 301 | greg | 1.11 | castonly = 0; | 
| 302 | greg | 1.1 | break; | 
| 303 | greg | 2.29 | case 'c':                               /* local coordinates */ | 
| 304 |  |  | *table++ = oputc; | 
| 305 | greg | 2.91 | ncomp += 2; | 
| 306 | greg | 2.29 | break; | 
| 307 | greg | 2.5 | case 'L':                               /* single ray length */ | 
| 308 |  |  | *table++ = oputL; | 
| 309 | greg | 2.91 | ncomp++; | 
| 310 | greg | 2.5 | break; | 
| 311 | greg | 1.1 | case 'p':                               /* point */ | 
| 312 |  |  | *table++ = oputp; | 
| 313 | greg | 2.91 | ncomp += 3; | 
| 314 | greg | 1.1 | break; | 
| 315 | greg | 2.9 | case 'n':                               /* perturbed normal */ | 
| 316 | greg | 1.1 | *table++ = oputn; | 
| 317 | greg | 2.91 | ncomp += 3; | 
| 318 | greg | 2.9 | castonly = 0; | 
| 319 | greg | 1.1 | break; | 
| 320 | greg | 2.9 | case 'N':                               /* unperturbed normal */ | 
| 321 |  |  | *table++ = oputN; | 
| 322 | greg | 2.91 | ncomp += 3; | 
| 323 | greg | 2.9 | break; | 
| 324 | greg | 1.1 | case 's':                               /* surface */ | 
| 325 |  |  | *table++ = oputs; | 
| 326 | greg | 2.91 | ncomp++; | 
| 327 | greg | 1.1 | break; | 
| 328 |  |  | case 'w':                               /* weight */ | 
| 329 |  |  | *table++ = oputw; | 
| 330 | greg | 2.91 | ncomp++; | 
| 331 | greg | 1.1 | break; | 
| 332 | greg | 2.40 | case 'W':                               /* coefficient */ | 
| 333 |  |  | *table++ = oputW; | 
| 334 | greg | 2.91 | ncomp += 3; | 
| 335 | greg | 2.73 | castonly = 0; | 
| 336 | greg | 2.80 | if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0)) | 
| 337 | greg | 2.40 | error(WARNING, | 
| 338 | greg | 2.41 | "-otW accuracy depends on -aa 0 -as 0"); | 
| 339 | greg | 2.40 | break; | 
| 340 | greg | 1.1 | case 'm':                               /* modifier */ | 
| 341 |  |  | *table++ = oputm; | 
| 342 | greg | 2.91 | ncomp++; | 
| 343 | greg | 1.1 | break; | 
| 344 | greg | 2.39 | case 'M':                               /* material */ | 
| 345 |  |  | *table++ = oputM; | 
| 346 | greg | 2.91 | ncomp++; | 
| 347 | greg | 2.39 | break; | 
| 348 | greg | 2.42 | case '~':                               /* tilde */ | 
| 349 |  |  | *table++ = oputtilde; | 
| 350 | greg | 2.41 | break; | 
| 351 | greg | 2.91 | default: | 
| 352 |  |  | sprintf(errmsg, "unrecognized output option '%c'", *vs); | 
| 353 |  |  | error(USER, errmsg); | 
| 354 | greg | 1.1 | } | 
| 355 | greg | 2.91 | while (*++vs); | 
| 356 |  |  |  | 
| 357 | greg | 1.1 | *table = NULL; | 
| 358 | greg | 2.91 | if (*every_out != NULL) | 
| 359 |  |  | ncomp = 0; | 
| 360 | greg | 2.81 | /* compatibility */ | 
| 361 | greg | 2.94 | if ((do_irrad | imm_irrad) && castonly) | 
| 362 |  |  | error(USER, "-I+ and -i+ options require some value output"); | 
| 363 | greg | 2.81 | for (table = ray_out; *table != NULL; table++) { | 
| 364 |  |  | if ((*table == oputV) | (*table == oputW)) | 
| 365 |  |  | error(WARNING, "-oVW options require trace mode"); | 
| 366 |  |  | if ((do_irrad | imm_irrad) && | 
| 367 |  |  | (*table == oputr) | (*table == oputR) | | 
| 368 |  |  | (*table == oputx) | (*table == oputX)) | 
| 369 |  |  | error(WARNING, "-orRxX options incompatible with -I+ and -i+"); | 
| 370 |  |  | } | 
| 371 | greg | 2.91 | return(ncomp); | 
| 372 | gregl | 2.24 | } | 
| 373 |  |  |  | 
| 374 |  |  |  | 
| 375 | schorsch | 2.37 | static void | 
| 376 |  |  | bogusray(void)                  /* print out empty record */ | 
| 377 | gregl | 2.24 | { | 
| 378 | greg | 2.40 | rayorigin(&thisray, PRIMARY, NULL, NULL); | 
| 379 | gregl | 2.24 | printvals(&thisray); | 
| 380 | greg | 1.1 | } | 
| 381 |  |  |  | 
| 382 |  |  |  | 
| 383 | schorsch | 2.37 | static void | 
| 384 | greg | 2.59 | raycast(                        /* compute first ray intersection only */ | 
| 385 |  |  | RAY *r | 
| 386 | schorsch | 2.37 | ) | 
| 387 | greg | 1.1 | { | 
| 388 | greg | 2.59 | if (!localhit(r, &thescene)) { | 
| 389 |  |  | if (r->ro == &Aftplane) {       /* clipped */ | 
| 390 |  |  | r->ro = NULL; | 
| 391 |  |  | r->rot = FHUGE; | 
| 392 |  |  | } else | 
| 393 |  |  | sourcehit(r); | 
| 394 | greg | 2.57 | } | 
| 395 | greg | 1.1 | } | 
| 396 |  |  |  | 
| 397 |  |  |  | 
| 398 | schorsch | 2.37 | static void | 
| 399 | greg | 2.59 | rayirrad(                       /* compute irradiance rather than radiance */ | 
| 400 |  |  | RAY *r | 
| 401 |  |  | ) | 
| 402 |  |  | { | 
| 403 | greg | 2.62 | void    (*old_revf)(RAY *) = r->revf; | 
| 404 | greg | 2.75 | /* pretend we hit surface */ | 
| 405 | greg | 2.76 | r->rxt = r->rot = 1e-5; | 
| 406 | greg | 2.59 | VSUM(r->rop, r->rorg, r->rdir, r->rot); | 
| 407 |  |  | r->ron[0] = -r->rdir[0]; | 
| 408 |  |  | r->ron[1] = -r->rdir[1]; | 
| 409 |  |  | r->ron[2] = -r->rdir[2]; | 
| 410 |  |  | r->rod = 1.0; | 
| 411 | greg | 2.62 | /* compute result */ | 
| 412 | greg | 2.61 | r->revf = raytrace; | 
| 413 | greg | 2.59 | (*ofun[Lamb.otype].funp)(&Lamb, r); | 
| 414 | greg | 2.62 | r->revf = old_revf; | 
| 415 | greg | 2.59 | } | 
| 416 |  |  |  | 
| 417 |  |  |  | 
| 418 |  |  | static void | 
| 419 |  |  | rtcompute(                      /* compute and print ray value(s) */ | 
| 420 | schorsch | 2.37 | FVECT  org, | 
| 421 | greg | 2.59 | FVECT  dir, | 
| 422 |  |  | double  dmax | 
| 423 | schorsch | 2.37 | ) | 
| 424 | greg | 1.1 | { | 
| 425 | greg | 2.60 | /* set up ray */ | 
| 426 |  |  | if (imm_irrad) { | 
| 427 | greg | 2.59 | VSUM(thisray.rorg, org, dir, 1.1e-4); | 
| 428 |  |  | thisray.rdir[0] = -dir[0]; | 
| 429 |  |  | thisray.rdir[1] = -dir[1]; | 
| 430 |  |  | thisray.rdir[2] = -dir[2]; | 
| 431 |  |  | thisray.rmax = 0.0; | 
| 432 |  |  | } else { | 
| 433 |  |  | VCOPY(thisray.rorg, org); | 
| 434 |  |  | VCOPY(thisray.rdir, dir); | 
| 435 |  |  | thisray.rmax = dmax; | 
| 436 |  |  | } | 
| 437 | greg | 2.101 | rayorigin(&thisray, PRIMARY, NULL, NULL); | 
| 438 |  |  | if (imm_irrad) | 
| 439 |  |  | thisray.revf = rayirrad; | 
| 440 |  |  | else if (castonly) | 
| 441 |  |  | thisray.revf = raycast; | 
| 442 | greg | 2.59 | if (ray_pnprocs > 1) {          /* multiprocessing FIFO? */ | 
| 443 |  |  | if (ray_fifo_in(&thisray) < 0) | 
| 444 |  |  | error(USER, "lost children"); | 
| 445 |  |  | return; | 
| 446 |  |  | } | 
| 447 |  |  | samplendx++;                    /* else do it ourselves */ | 
| 448 |  |  | rayvalue(&thisray); | 
| 449 | greg | 2.16 | printvals(&thisray); | 
| 450 |  |  | } | 
| 451 |  |  |  | 
| 452 |  |  |  | 
| 453 | greg | 2.57 | static int | 
| 454 | schorsch | 2.37 | printvals(                      /* print requested ray values */ | 
| 455 |  |  | RAY  *r | 
| 456 |  |  | ) | 
| 457 | greg | 2.16 | { | 
| 458 | greg | 2.56 | oputf_t **tp; | 
| 459 | greg | 2.16 |  | 
| 460 |  |  | if (ray_out[0] == NULL) | 
| 461 | greg | 2.57 | return(0); | 
| 462 | greg | 2.16 | for (tp = ray_out; *tp != NULL; tp++) | 
| 463 |  |  | (**tp)(r); | 
| 464 | greg | 1.1 | if (outform == 'a') | 
| 465 |  |  | putchar('\n'); | 
| 466 | greg | 2.57 | return(1); | 
| 467 | greg | 1.1 | } | 
| 468 |  |  |  | 
| 469 |  |  |  | 
| 470 | schorsch | 2.37 | static int | 
| 471 | greg | 2.92 | is_fifo(                /* check if file pointer connected to pipe */ | 
| 472 |  |  | FILE *fp | 
| 473 |  |  | ) | 
| 474 |  |  | { | 
| 475 |  |  | #ifdef S_ISFIFO | 
| 476 |  |  | struct stat  sbuf; | 
| 477 |  |  |  | 
| 478 |  |  | if (fstat(fileno(fp), &sbuf) < 0) | 
| 479 |  |  | error(SYSTEM, "fstat() failed on input stream"); | 
| 480 |  |  | return(S_ISFIFO(sbuf.st_mode)); | 
| 481 |  |  | #else | 
| 482 |  |  | return (fp == stdin);           /* just a guess, really */ | 
| 483 |  |  | #endif | 
| 484 |  |  | } | 
| 485 |  |  |  | 
| 486 |  |  |  | 
| 487 |  |  | static int | 
| 488 | greg | 2.89 | getvec(                 /* get a vector from fp */ | 
| 489 | greg | 2.56 | FVECT  vec, | 
| 490 | schorsch | 2.37 | int  fmt, | 
| 491 |  |  | FILE  *fp | 
| 492 |  |  | ) | 
| 493 | greg | 1.1 | { | 
| 494 |  |  | static float  vf[3]; | 
| 495 | greg | 2.5 | static double  vd[3]; | 
| 496 | greg | 1.19 | char  buf[32]; | 
| 497 | greg | 2.56 | int  i; | 
| 498 | greg | 1.1 |  | 
| 499 |  |  | switch (fmt) { | 
| 500 |  |  | case 'a':                                       /* ascii */ | 
| 501 | greg | 1.19 | for (i = 0; i < 3; i++) { | 
| 502 |  |  | if (fgetword(buf, sizeof(buf), fp) == NULL || | 
| 503 |  |  | !isflt(buf)) | 
| 504 |  |  | return(-1); | 
| 505 |  |  | vec[i] = atof(buf); | 
| 506 |  |  | } | 
| 507 | greg | 1.1 | break; | 
| 508 |  |  | case 'f':                                       /* binary float */ | 
| 509 | greg | 2.70 | if (getbinary(vf, sizeof(float), 3, fp) != 3) | 
| 510 | greg | 1.1 | return(-1); | 
| 511 | greg | 2.58 | VCOPY(vec, vf); | 
| 512 | greg | 1.1 | break; | 
| 513 |  |  | case 'd':                                       /* binary double */ | 
| 514 | greg | 2.70 | if (getbinary(vd, sizeof(double), 3, fp) != 3) | 
| 515 | greg | 1.1 | return(-1); | 
| 516 | greg | 2.58 | VCOPY(vec, vd); | 
| 517 | greg | 1.1 | break; | 
| 518 | greg | 2.6 | default: | 
| 519 |  |  | error(CONSISTENCY, "botched input format"); | 
| 520 | greg | 1.1 | } | 
| 521 |  |  | return(0); | 
| 522 |  |  | } | 
| 523 |  |  |  | 
| 524 |  |  |  | 
| 525 | greg | 2.89 | static int | 
| 526 |  |  | iszerovec(const FVECT vec) | 
| 527 |  |  | { | 
| 528 |  |  | return (vec[0] == 0.0) & (vec[1] == 0.0) & (vec[2] == 0.0); | 
| 529 |  |  | } | 
| 530 |  |  |  | 
| 531 |  |  |  | 
| 532 |  |  | static double | 
| 533 |  |  | nextray(                /* return next ray in work group (-1.0 if EOF) */ | 
| 534 |  |  | FVECT org, | 
| 535 |  |  | FVECT dir | 
| 536 |  |  | ) | 
| 537 |  |  | { | 
| 538 |  |  | const size_t    qlength = !vresolu * hresolu; | 
| 539 |  |  |  | 
| 540 |  |  | if ((org == NULL) | (dir == NULL)) { | 
| 541 |  |  | if (inp_queue != NULL)  /* asking to free queue */ | 
| 542 |  |  | free(inp_queue); | 
| 543 |  |  | inp_queue = NULL; | 
| 544 |  |  | inp_qpos = inp_qend = 0; | 
| 545 |  |  | return(-1.); | 
| 546 |  |  | } | 
| 547 |  |  | if (!inp_qend) {                /* initialize FIFO queue */ | 
| 548 |  |  | int     rsiz = 6*20;    /* conservative ascii ray size */ | 
| 549 |  |  | if (inform == 'f') rsiz = 6*sizeof(float); | 
| 550 |  |  | else if (inform == 'd') rsiz = 6*sizeof(double); | 
| 551 | greg | 2.92 | /* check against pipe limit */ | 
| 552 |  |  | if (qlength*rsiz > 512 && is_fifo(inpfp)) | 
| 553 | greg | 2.89 | inp_queue = (FVECT *)malloc(sizeof(FVECT)*2*qlength); | 
| 554 |  |  | inp_qend = -(inp_queue == NULL);        /* flag for no queue */ | 
| 555 |  |  | } | 
| 556 |  |  | if (inp_qend < 0) {             /* not queuing? */ | 
| 557 |  |  | if (getvec(org, inform, inpfp) < 0 || | 
| 558 |  |  | getvec(dir, inform, inpfp) < 0) | 
| 559 |  |  | return(-1.); | 
| 560 |  |  | return normalize(dir); | 
| 561 |  |  | } | 
| 562 |  |  | if (inp_qpos >= inp_qend) {     /* need to refill input queue? */ | 
| 563 |  |  | for (inp_qend = 0; inp_qend < qlength; inp_qend++) { | 
| 564 |  |  | if (getvec(inp_queue[2*inp_qend], inform, inpfp) < 0 | 
| 565 |  |  | || getvec(inp_queue[2*inp_qend+1], | 
| 566 |  |  | inform, inpfp) < 0) | 
| 567 |  |  | break;          /* hit EOF */ | 
| 568 |  |  | if (iszerovec(inp_queue[2*inp_qend+1])) { | 
| 569 |  |  | ++inp_qend;     /* flush request */ | 
| 570 |  |  | break; | 
| 571 |  |  | } | 
| 572 |  |  | } | 
| 573 |  |  | inp_qpos = 0; | 
| 574 |  |  | } | 
| 575 |  |  | if (inp_qpos >= inp_qend)       /* unexpected EOF? */ | 
| 576 |  |  | return(-1.); | 
| 577 |  |  | VCOPY(org, inp_queue[2*inp_qpos]); | 
| 578 |  |  | VCOPY(dir, inp_queue[2*inp_qpos+1]); | 
| 579 |  |  | ++inp_qpos; | 
| 580 |  |  | return normalize(dir); | 
| 581 |  |  | } | 
| 582 |  |  |  | 
| 583 |  |  |  | 
| 584 | greg | 2.57 | void | 
| 585 | schorsch | 2.37 | tranotify(                      /* record new modifier */ | 
| 586 |  |  | OBJECT  obj | 
| 587 |  |  | ) | 
| 588 | greg | 2.15 | { | 
| 589 |  |  | static int  hitlimit = 0; | 
| 590 | greg | 2.56 | OBJREC   *o = objptr(obj); | 
| 591 |  |  | char  **tralp; | 
| 592 | greg | 2.15 |  | 
| 593 | greg | 2.27 | if (obj == OVOID) {             /* starting over */ | 
| 594 |  |  | traset[0] = 0; | 
| 595 |  |  | hitlimit = 0; | 
| 596 |  |  | return; | 
| 597 |  |  | } | 
| 598 | greg | 2.15 | if (hitlimit || !ismodifier(o->otype)) | 
| 599 |  |  | return; | 
| 600 |  |  | for (tralp = tralist; *tralp != NULL; tralp++) | 
| 601 |  |  | if (!strcmp(o->oname, *tralp)) { | 
| 602 |  |  | if (traset[0] >= MAXTSET) { | 
| 603 |  |  | error(WARNING, "too many modifiers in trace list"); | 
| 604 |  |  | hitlimit++; | 
| 605 |  |  | return;         /* should this be fatal? */ | 
| 606 |  |  | } | 
| 607 |  |  | insertelem(traset, obj); | 
| 608 |  |  | return; | 
| 609 |  |  | } | 
| 610 |  |  | } | 
| 611 |  |  |  | 
| 612 |  |  |  | 
| 613 | greg | 2.27 | static void | 
| 614 | schorsch | 2.37 | ourtrace(                               /* print ray values */ | 
| 615 |  |  | RAY  *r | 
| 616 |  |  | ) | 
| 617 | greg | 1.1 | { | 
| 618 | greg | 2.56 | oputf_t **tp; | 
| 619 | greg | 1.1 |  | 
| 620 |  |  | if (every_out[0] == NULL) | 
| 621 | greg | 2.15 | return; | 
| 622 | greg | 2.16 | if (r->ro == NULL) { | 
| 623 |  |  | if (traincl == 1) | 
| 624 |  |  | return; | 
| 625 |  |  | } else if (traincl != -1 && traincl != inset(traset, r->ro->omod)) | 
| 626 | greg | 1.1 | return; | 
| 627 |  |  | tabin(r); | 
| 628 |  |  | for (tp = every_out; *tp != NULL; tp++) | 
| 629 |  |  | (**tp)(r); | 
| 630 | greg | 2.41 | if (outform == 'a') | 
| 631 |  |  | putchar('\n'); | 
| 632 | greg | 1.1 | } | 
| 633 |  |  |  | 
| 634 |  |  |  | 
| 635 | greg | 2.27 | static void | 
| 636 | schorsch | 2.37 | tabin(                          /* tab in appropriate amount */ | 
| 637 |  |  | RAY  *r | 
| 638 |  |  | ) | 
| 639 | greg | 1.1 | { | 
| 640 | greg | 2.40 | const RAY  *rp; | 
| 641 | greg | 1.1 |  | 
| 642 |  |  | for (rp = r->parent; rp != NULL; rp = rp->parent) | 
| 643 |  |  | putchar('\t'); | 
| 644 |  |  | } | 
| 645 |  |  |  | 
| 646 |  |  |  | 
| 647 | greg | 2.27 | static void | 
| 648 | schorsch | 2.37 | oputo(                          /* print origin */ | 
| 649 |  |  | RAY  *r | 
| 650 |  |  | ) | 
| 651 | greg | 1.1 | { | 
| 652 | greg | 2.65 | (*putreal)(r->rorg, 3); | 
| 653 | greg | 1.1 | } | 
| 654 |  |  |  | 
| 655 |  |  |  | 
| 656 | greg | 2.27 | static void | 
| 657 | schorsch | 2.37 | oputd(                          /* print direction */ | 
| 658 |  |  | RAY  *r | 
| 659 |  |  | ) | 
| 660 | greg | 1.1 | { | 
| 661 | greg | 2.65 | (*putreal)(r->rdir, 3); | 
| 662 | greg | 1.1 | } | 
| 663 |  |  |  | 
| 664 |  |  |  | 
| 665 | greg | 2.27 | static void | 
| 666 | greg | 2.73 | oputr(                          /* print mirrored contribution */ | 
| 667 |  |  | RAY  *r | 
| 668 |  |  | ) | 
| 669 |  |  | { | 
| 670 |  |  | RREAL   cval[3]; | 
| 671 |  |  |  | 
| 672 |  |  | cval[0] = colval(r->mcol,RED); | 
| 673 |  |  | cval[1] = colval(r->mcol,GRN); | 
| 674 |  |  | cval[2] = colval(r->mcol,BLU); | 
| 675 |  |  | (*putreal)(cval, 3); | 
| 676 |  |  | } | 
| 677 |  |  |  | 
| 678 |  |  |  | 
| 679 |  |  |  | 
| 680 |  |  | static void | 
| 681 |  |  | oputR(                          /* print mirrored distance */ | 
| 682 |  |  | RAY  *r | 
| 683 |  |  | ) | 
| 684 |  |  | { | 
| 685 |  |  | (*putreal)(&r->rmt, 1); | 
| 686 |  |  | } | 
| 687 |  |  |  | 
| 688 |  |  |  | 
| 689 |  |  | static void | 
| 690 |  |  | oputx(                          /* print unmirrored contribution */ | 
| 691 |  |  | RAY  *r | 
| 692 |  |  | ) | 
| 693 |  |  | { | 
| 694 |  |  | RREAL   cval[3]; | 
| 695 |  |  |  | 
| 696 |  |  | cval[0] = colval(r->rcol,RED) - colval(r->mcol,RED); | 
| 697 |  |  | cval[1] = colval(r->rcol,GRN) - colval(r->mcol,GRN); | 
| 698 |  |  | cval[2] = colval(r->rcol,BLU) - colval(r->mcol,BLU); | 
| 699 |  |  | (*putreal)(cval, 3); | 
| 700 |  |  | } | 
| 701 |  |  |  | 
| 702 |  |  |  | 
| 703 |  |  | static void | 
| 704 |  |  | oputX(                          /* print unmirrored distance */ | 
| 705 |  |  | RAY  *r | 
| 706 |  |  | ) | 
| 707 |  |  | { | 
| 708 |  |  | (*putreal)(&r->rxt, 1); | 
| 709 |  |  | } | 
| 710 |  |  |  | 
| 711 |  |  |  | 
| 712 |  |  | static void | 
| 713 | schorsch | 2.37 | oputv(                          /* print value */ | 
| 714 |  |  | RAY  *r | 
| 715 |  |  | ) | 
| 716 | greg | 1.1 | { | 
| 717 | greg | 2.65 | RREAL   cval[3]; | 
| 718 |  |  |  | 
| 719 |  |  | cval[0] = colval(r->rcol,RED); | 
| 720 |  |  | cval[1] = colval(r->rcol,GRN); | 
| 721 |  |  | cval[2] = colval(r->rcol,BLU); | 
| 722 |  |  | (*putreal)(cval, 3); | 
| 723 | greg | 1.1 | } | 
| 724 |  |  |  | 
| 725 |  |  |  | 
| 726 | greg | 2.27 | static void | 
| 727 | greg | 2.51 | oputV(                          /* print value contribution */ | 
| 728 |  |  | RAY *r | 
| 729 |  |  | ) | 
| 730 |  |  | { | 
| 731 | greg | 2.65 | RREAL   contr[3]; | 
| 732 | greg | 2.51 |  | 
| 733 |  |  | raycontrib(contr, r, PRIMARY); | 
| 734 |  |  | multcolor(contr, r->rcol); | 
| 735 | greg | 2.65 | (*putreal)(contr, 3); | 
| 736 | greg | 2.51 | } | 
| 737 |  |  |  | 
| 738 |  |  |  | 
| 739 |  |  | static void | 
| 740 | schorsch | 2.37 | oputl(                          /* print effective distance */ | 
| 741 |  |  | RAY  *r | 
| 742 |  |  | ) | 
| 743 | greg | 1.1 | { | 
| 744 | greg | 2.73 | RREAL   d = raydistance(r); | 
| 745 |  |  |  | 
| 746 |  |  | (*putreal)(&d, 1); | 
| 747 | greg | 2.5 | } | 
| 748 |  |  |  | 
| 749 |  |  |  | 
| 750 | greg | 2.27 | static void | 
| 751 | schorsch | 2.37 | oputL(                          /* print single ray length */ | 
| 752 |  |  | RAY  *r | 
| 753 |  |  | ) | 
| 754 | greg | 2.5 | { | 
| 755 | greg | 2.65 | (*putreal)(&r->rot, 1); | 
| 756 | greg | 1.1 | } | 
| 757 |  |  |  | 
| 758 |  |  |  | 
| 759 | greg | 2.27 | static void | 
| 760 | schorsch | 2.37 | oputc(                          /* print local coordinates */ | 
| 761 |  |  | RAY  *r | 
| 762 |  |  | ) | 
| 763 | greg | 2.29 | { | 
| 764 | greg | 2.65 | (*putreal)(r->uv, 2); | 
| 765 | greg | 2.29 | } | 
| 766 |  |  |  | 
| 767 |  |  |  | 
| 768 | greg | 2.65 | static RREAL    vdummy[3] = {0.0, 0.0, 0.0}; | 
| 769 |  |  |  | 
| 770 |  |  |  | 
| 771 | greg | 2.29 | static void | 
| 772 | greg | 2.100 | oputp(                          /* print intersection point */ | 
| 773 | schorsch | 2.37 | RAY  *r | 
| 774 |  |  | ) | 
| 775 | greg | 1.1 | { | 
| 776 | greg | 2.100 | (*putreal)(r->rop, 3);  /* set to ray origin if distant or no hit */ | 
| 777 | greg | 1.1 | } | 
| 778 |  |  |  | 
| 779 |  |  |  | 
| 780 | greg | 2.27 | static void | 
| 781 | schorsch | 2.37 | oputN(                          /* print unperturbed normal */ | 
| 782 |  |  | RAY  *r | 
| 783 |  |  | ) | 
| 784 | greg | 1.1 | { | 
| 785 | greg | 2.100 | if (r->ro == NULL) {    /* zero vector if clipped or no hit */ | 
| 786 |  |  | (*putreal)(vdummy, 3); | 
| 787 |  |  | return; | 
| 788 |  |  | } | 
| 789 |  |  | if (r->rflips & 1) {    /* undo any flippin' flips */ | 
| 790 |  |  | FVECT   unrm; | 
| 791 |  |  | unrm[0] = -r->ron[0]; | 
| 792 |  |  | unrm[1] = -r->ron[1]; | 
| 793 |  |  | unrm[2] = -r->ron[2]; | 
| 794 |  |  | (*putreal)(unrm, 3); | 
| 795 | greg | 2.82 | } else | 
| 796 | greg | 2.100 | (*putreal)(r->ron, 3); | 
| 797 | greg | 2.9 | } | 
| 798 |  |  |  | 
| 799 |  |  |  | 
| 800 | greg | 2.27 | static void | 
| 801 | schorsch | 2.37 | oputn(                          /* print perturbed normal */ | 
| 802 |  |  | RAY  *r | 
| 803 |  |  | ) | 
| 804 | greg | 2.9 | { | 
| 805 |  |  | FVECT  pnorm; | 
| 806 |  |  |  | 
| 807 | greg | 2.100 | if (r->ro == NULL) {    /* clipped or no hit */ | 
| 808 | greg | 2.65 | (*putreal)(vdummy, 3); | 
| 809 | greg | 2.9 | return; | 
| 810 |  |  | } | 
| 811 |  |  | raynormal(pnorm, r); | 
| 812 | greg | 2.65 | (*putreal)(pnorm, 3); | 
| 813 | greg | 1.1 | } | 
| 814 |  |  |  | 
| 815 |  |  |  | 
| 816 | greg | 2.27 | static void | 
| 817 | schorsch | 2.37 | oputs(                          /* print name */ | 
| 818 |  |  | RAY  *r | 
| 819 |  |  | ) | 
| 820 | greg | 1.1 | { | 
| 821 |  |  | if (r->ro != NULL) | 
| 822 |  |  | fputs(r->ro->oname, stdout); | 
| 823 |  |  | else | 
| 824 |  |  | putchar('*'); | 
| 825 |  |  | putchar('\t'); | 
| 826 |  |  | } | 
| 827 |  |  |  | 
| 828 |  |  |  | 
| 829 | greg | 2.27 | static void | 
| 830 | schorsch | 2.37 | oputw(                          /* print weight */ | 
| 831 |  |  | RAY  *r | 
| 832 |  |  | ) | 
| 833 | greg | 1.1 | { | 
| 834 | greg | 2.65 | RREAL   rwt = r->rweight; | 
| 835 |  |  |  | 
| 836 |  |  | (*putreal)(&rwt, 1); | 
| 837 | greg | 1.1 | } | 
| 838 |  |  |  | 
| 839 |  |  |  | 
| 840 | greg | 2.27 | static void | 
| 841 | greg | 2.51 | oputW(                          /* print coefficient */ | 
| 842 | greg | 2.40 | RAY  *r | 
| 843 |  |  | ) | 
| 844 |  |  | { | 
| 845 | greg | 2.65 | RREAL   contr[3]; | 
| 846 | greg | 2.67 | /* shadow ray not on source? */ | 
| 847 |  |  | if (r->rsrc >= 0 && source[r->rsrc].so != r->ro) | 
| 848 |  |  | setcolor(contr, 0.0, 0.0, 0.0); | 
| 849 |  |  | else | 
| 850 |  |  | raycontrib(contr, r, PRIMARY); | 
| 851 | greg | 2.40 |  | 
| 852 | greg | 2.65 | (*putreal)(contr, 3); | 
| 853 | greg | 2.40 | } | 
| 854 |  |  |  | 
| 855 |  |  |  | 
| 856 |  |  | static void | 
| 857 | schorsch | 2.37 | oputm(                          /* print modifier */ | 
| 858 |  |  | RAY  *r | 
| 859 |  |  | ) | 
| 860 | greg | 1.1 | { | 
| 861 |  |  | if (r->ro != NULL) | 
| 862 | greg | 2.23 | if (r->ro->omod != OVOID) | 
| 863 |  |  | fputs(objptr(r->ro->omod)->oname, stdout); | 
| 864 |  |  | else | 
| 865 |  |  | fputs(VOIDID, stdout); | 
| 866 | greg | 1.1 | else | 
| 867 |  |  | putchar('*'); | 
| 868 |  |  | putchar('\t'); | 
| 869 |  |  | } | 
| 870 |  |  |  | 
| 871 |  |  |  | 
| 872 | greg | 2.27 | static void | 
| 873 | greg | 2.39 | oputM(                          /* print material */ | 
| 874 |  |  | RAY  *r | 
| 875 |  |  | ) | 
| 876 |  |  | { | 
| 877 |  |  | OBJREC  *mat; | 
| 878 |  |  |  | 
| 879 |  |  | if (r->ro != NULL) { | 
| 880 |  |  | if ((mat = findmaterial(r->ro)) != NULL) | 
| 881 |  |  | fputs(mat->oname, stdout); | 
| 882 |  |  | else | 
| 883 |  |  | fputs(VOIDID, stdout); | 
| 884 |  |  | } else | 
| 885 |  |  | putchar('*'); | 
| 886 |  |  | putchar('\t'); | 
| 887 |  |  | } | 
| 888 |  |  |  | 
| 889 |  |  |  | 
| 890 |  |  | static void | 
| 891 | greg | 2.42 | oputtilde(                      /* output tilde (spacer) */ | 
| 892 | greg | 2.41 | RAY  *r | 
| 893 |  |  | ) | 
| 894 |  |  | { | 
| 895 | greg | 2.42 | fputs("~\t", stdout); | 
| 896 | greg | 2.41 | } | 
| 897 |  |  |  | 
| 898 |  |  |  | 
| 899 |  |  | static void | 
| 900 | greg | 2.65 | puta(                           /* print ascii value(s) */ | 
| 901 |  |  | RREAL *v, int n | 
| 902 | schorsch | 2.37 | ) | 
| 903 | greg | 1.1 | { | 
| 904 | greg | 2.65 | if (n == 3) { | 
| 905 |  |  | printf("%e\t%e\t%e\t", v[0], v[1], v[2]); | 
| 906 |  |  | return; | 
| 907 |  |  | } | 
| 908 |  |  | while (n--) | 
| 909 |  |  | printf("%e\t", *v++); | 
| 910 | greg | 1.1 | } | 
| 911 |  |  |  | 
| 912 |  |  |  | 
| 913 | greg | 2.27 | static void | 
| 914 | greg | 2.80 | putd(RREAL *v, int n)           /* output binary double(s) */ | 
| 915 | greg | 1.1 | { | 
| 916 | greg | 2.68 | #ifdef  SMLFLT | 
| 917 |  |  | double  da[3]; | 
| 918 |  |  | int     i; | 
| 919 |  |  |  | 
| 920 |  |  | if (n > 3) | 
| 921 | greg | 2.65 | error(INTERNAL, "code error in putd()"); | 
| 922 | greg | 2.68 | for (i = n; i--; ) | 
| 923 |  |  | da[i] = v[i]; | 
| 924 | greg | 2.69 | putbinary(da, sizeof(double), n, stdout); | 
| 925 | greg | 2.68 | #else | 
| 926 | greg | 2.69 | putbinary(v, sizeof(RREAL), n, stdout); | 
| 927 | greg | 2.68 | #endif | 
| 928 | greg | 1.1 | } | 
| 929 |  |  |  | 
| 930 |  |  |  | 
| 931 | greg | 2.27 | static void | 
| 932 | greg | 2.80 | putf(RREAL *v, int n)           /* output binary float(s) */ | 
| 933 | greg | 1.1 | { | 
| 934 | greg | 2.68 | #ifndef SMLFLT | 
| 935 | greg | 2.65 | float   fa[3]; | 
| 936 |  |  | int     i; | 
| 937 | greg | 1.1 |  | 
| 938 | greg | 2.65 | if (n > 3) | 
| 939 |  |  | error(INTERNAL, "code error in putf()"); | 
| 940 |  |  | for (i = n; i--; ) | 
| 941 |  |  | fa[i] = v[i]; | 
| 942 | greg | 2.69 | putbinary(fa, sizeof(float), n, stdout); | 
| 943 | greg | 2.68 | #else | 
| 944 | greg | 2.69 | putbinary(v, sizeof(RREAL), n, stdout); | 
| 945 | greg | 2.68 | #endif | 
| 946 | greg | 1.1 | } | 
| 947 | greg | 2.80 |  | 
| 948 |  |  |  | 
| 949 |  |  | static void | 
| 950 |  |  | putrgbe(RREAL *v, int n)        /* output RGBE color */ | 
| 951 |  |  | { | 
| 952 |  |  | COLR  cout; | 
| 953 |  |  |  | 
| 954 |  |  | if (n != 3) | 
| 955 |  |  | error(INTERNAL, "putrgbe() not called with 3 components"); | 
| 956 |  |  | setcolr(cout, v[0], v[1], v[2]); | 
| 957 |  |  | putbinary(cout, sizeof(cout), 1, stdout); | 
| 958 |  |  | } |