| 6 |  | * Initialization and calculation routines | 
| 7 |  | */ | 
| 8 |  |  | 
| 9 | + | #include "copyright.h" | 
| 10 | + |  | 
| 11 | + | #include <ctype.h> | 
| 12 |  | #include "rcontrib.h" | 
| 10 | – | #include "source.h" | 
| 13 |  | #include "otypes.h" | 
| 14 | < | #include "platform.h" | 
| 14 | > | #include "source.h" | 
| 15 |  |  | 
| 16 | + | char    *shm_boundary = NULL;           /* boundary of shared memory */ | 
| 17 | + |  | 
| 18 |  | CUBE    thescene;                       /* our scene */ | 
| 19 |  | OBJECT  nsceneobjs;                     /* number of objects in our scene */ | 
| 20 |  |  | 
| 27 |  |  | 
| 28 |  | int     do_irrad = 0;                   /* compute irradiance? */ | 
| 29 |  |  | 
| 30 | < | int     rand_samp = 0;                  /* pure Monte Carlo sampling? */ | 
| 30 | > | int     rand_samp = 1;                  /* pure Monte Carlo sampling? */ | 
| 31 |  |  | 
| 32 | < | double  dstrsrc = 0.0;                  /* square source distribution */ | 
| 32 | > | double  dstrsrc = 0.9;                  /* square source distribution */ | 
| 33 |  | double  shadthresh = .03;               /* shadow threshold */ | 
| 34 |  | double  shadcert = .75;                 /* shadow certainty */ | 
| 35 |  | int     directrelay = 3;                /* number of source relays */ | 
| 47 |  |  | 
| 48 |  | int     backvis = 1;                    /* back face visibility */ | 
| 49 |  |  | 
| 50 | < | int     maxdepth = 8;                   /* maximum recursion depth */ | 
| 51 | < | double  minweight = 5e-4;               /* minimum ray weight */ | 
| 50 | > | int     maxdepth = -10;                 /* maximum recursion depth */ | 
| 51 | > | double  minweight = 2e-3;               /* minimum ray weight */ | 
| 52 |  |  | 
| 53 |  | char    *ambfile = NULL;                /* ambient file name */ | 
| 54 |  | COLOR   ambval = BLKCOLOR;              /* ambient value */ | 
| 65 |  | RNUMBER raysleft;                       /* number of rays left to trace */ | 
| 66 |  | long    waitflush;                      /* how long until next flush */ | 
| 67 |  |  | 
| 68 | < | int     lastray = 0;                    /* last ray number sent */ | 
| 69 | < | int     lastdone = 0;                   /* last ray output */ | 
| 68 | > | RNUMBER lastray = 0;                    /* last ray number sent */ | 
| 69 | > | RNUMBER lastdone = 0;                   /* last ray output */ | 
| 70 |  |  | 
| 67 | – | /* Close output stream and free record */ | 
| 68 | – | static void | 
| 69 | – | closestream(void *p) | 
| 70 | – | { | 
| 71 | – | STREAMOUT       *sop = (STREAMOUT *)p; | 
| 72 | – | int             status = 0; | 
| 73 | – | if (sop->outpipe) | 
| 74 | – | status = pclose(sop->ofp); | 
| 75 | – | else if (sop->ofp != stdout) | 
| 76 | – | status = fclose(sop->ofp); | 
| 77 | – | if (status) | 
| 78 | – | error(SYSTEM, "error closing output stream"); | 
| 79 | – | free(p); | 
| 80 | – | } | 
| 81 | – |  | 
| 82 | – | LUTAB   ofiletab = LU_SINIT(free,closestream);  /* output file table */ | 
| 83 | – |  | 
| 84 | – | #define OF_MODIFIER     01 | 
| 85 | – | #define OF_BIN          02 | 
| 86 | – |  | 
| 71 |  | static void mcfree(void *p) { epfree((*(MODCONT *)p).binv); free(p); } | 
| 72 |  |  | 
| 73 |  | LUTAB   modconttab = LU_SINIT(NULL,mcfree);     /* modifier lookup table */ | 
| 74 |  |  | 
| 91 | – | static OBJECT           traset[MAXTSET+1]={0};  /* trace include set */ | 
| 92 | – |  | 
| 75 |  | /************************** INITIALIZATION ROUTINES ***********************/ | 
| 76 |  |  | 
| 95 | – | void | 
| 96 | – | tranotify(                      /* record new modifier */ | 
| 97 | – | OBJECT  obj | 
| 98 | – | ) | 
| 99 | – | { | 
| 100 | – | static int      hitlimit = 0; | 
| 101 | – | OBJREC          *o = objptr(obj); | 
| 102 | – | int             i; | 
| 103 | – |  | 
| 104 | – | if (obj == OVOID) {             /* starting over */ | 
| 105 | – | traset[0] = 0; | 
| 106 | – | hitlimit = 0; | 
| 107 | – | return; | 
| 108 | – | } | 
| 109 | – | if (hitlimit || !ismodifier(o->otype)) | 
| 110 | – | return; | 
| 111 | – | for (i = nmods; i-- > 0; ) | 
| 112 | – | if (!strcmp(o->oname, modname[i])) { | 
| 113 | – | if (traset[0] >= MAXTSET) { | 
| 114 | – | error(WARNING, "too many same-named modifiers"); | 
| 115 | – | hitlimit++; | 
| 116 | – | return;         /* should this be fatal? */ | 
| 117 | – | } | 
| 118 | – | insertelem(traset, obj); | 
| 119 | – | break; | 
| 120 | – | } | 
| 121 | – | } | 
| 122 | – |  | 
| 123 | – |  | 
| 77 |  | char * | 
| 78 |  | formstr(                                /* return format identifier */ | 
| 79 |  | int  f | 
| 91 |  |  | 
| 92 |  | /* Add modifier to our list to track */ | 
| 93 |  | MODCONT * | 
| 94 | < | addmodifier(char *modn, char *outf, char *binv, int bincnt) | 
| 94 | > | addmodifier(char *modn, char *outf, char *prms, char *binv, int bincnt) | 
| 95 |  | { | 
| 96 |  | LUENT   *lep = lu_find(&modconttab,modn); | 
| 97 |  | MODCONT *mp; | 
| 128 |  | error(SYSTEM, "out of memory in addmodifier"); | 
| 129 |  | mp->outspec = outf;             /* XXX assumes static string */ | 
| 130 |  | mp->modname = modn;             /* XXX assumes static string */ | 
| 131 | + | mp->params = prms; | 
| 132 |  | mp->binv = ebinv; | 
| 133 |  | mp->nbins = bincnt; | 
| 134 |  | memset(mp->cbin, 0, sizeof(DCOLOR)*bincnt); | 
| 140 |  | } | 
| 141 |  |  | 
| 142 |  |  | 
| 143 | < | /* add modifiers from a file list */ | 
| 143 | > | /* Add modifiers from a file list */ | 
| 144 |  | void | 
| 145 | < | addmodfile(char *fname, char *outf, char *binv, int bincnt) | 
| 145 | > | addmodfile(char *fname, char *outf, char *prms, char *binv, int bincnt) | 
| 146 |  | { | 
| 147 |  | char    *mname[MAXMODLIST]; | 
| 148 |  | int     i; | 
| 152 |  | error(SYSTEM, errmsg); | 
| 153 |  | } | 
| 154 |  | for (i = 0; mname[i]; i++)      /* add each one */ | 
| 155 | < | addmodifier(mname[i], outf, binv, bincnt); | 
| 155 | > | addmodifier(mname[i], outf, prms, binv, bincnt); | 
| 156 |  | } | 
| 157 |  |  | 
| 158 |  |  | 
| 162 |  | ) | 
| 163 |  | { | 
| 164 |  | if (nchild > 0)         /* close children if any */ | 
| 165 | < | end_children(); | 
| 165 | > | end_children(code != 0); | 
| 166 |  | exit(code); | 
| 167 |  | } | 
| 168 |  |  | 
| 176 |  | if (nproc > MAXPROCESS) | 
| 177 |  | sprintf(errmsg, "too many processes requested -- reducing to %d", | 
| 178 |  | nproc = MAXPROCESS); | 
| 179 | < |  | 
| 180 | < | if ((nproc > 1) & (accumulate <= 0)) | 
| 181 | < | zero_record(0);         /* prime our queue to accumulate */ | 
| 182 | < |  | 
| 229 | < | if (recover) {                  /* recover previous output? */ | 
| 230 | < | if (accumulate <= 0) { | 
| 231 | < | reload_output(); | 
| 232 | < | if ((nproc > 1) & (accumulate <= 0)) | 
| 233 | < | queue_modifiers(); | 
| 234 | < | } else | 
| 235 | < | recover_output(); | 
| 179 | > | if (nproc > 1) { | 
| 180 | > | preload_objs();         /* preload auxiliary data */ | 
| 181 | > | /* set shared memory boundary */ | 
| 182 | > | shm_boundary = strcpy((char *)malloc(16), "SHM_BOUNDARY"); | 
| 183 |  | } | 
| 184 | + | for (i = 0; i < nsources; i++)  /* tracing to sources as well */ | 
| 185 | + | source[i].sflags |= SFOLLOW; | 
| 186 |  | if (yres > 0) {                 /* set up flushing & ray counts */ | 
| 187 |  | if (xres > 0) | 
| 188 |  | raysleft = (RNUMBER)xres*yres; | 
| 193 |  | if ((account = accumulate) > 1) | 
| 194 |  | raysleft *= accumulate; | 
| 195 |  | waitflush = (yres > 0) & (xres > 1) ? 0 : xres; | 
| 247 | – | /* tracing to sources as well */ | 
| 248 | – | for (i = 0; i < nsources; i++) | 
| 249 | – | source[i].sflags |= SFOLLOW; | 
| 196 |  |  | 
| 197 | < | if (nproc == 1 || in_rchild())  /* single process or child */ | 
| 197 | > | if (nproc > 1 && in_rchild())   /* forked child? */ | 
| 198 |  | return;                 /* return to main processing loop */ | 
| 199 |  |  | 
| 200 | < | parental_loop();                /* else run controller */ | 
| 200 | > | if (recover) {                  /* recover previous output? */ | 
| 201 | > | if (accumulate <= 0) | 
| 202 | > | reload_output(); | 
| 203 | > | else | 
| 204 | > | recover_output(); | 
| 205 | > | } | 
| 206 | > | if (nproc == 1)                 /* single process? */ | 
| 207 | > | return; | 
| 208 | > | /* else run appropriate controller */ | 
| 209 | > | if (accumulate <= 0) | 
| 210 | > | feeder_loop(); | 
| 211 | > | else | 
| 212 | > | parental_loop(); | 
| 213 |  | quit(0);                        /* parent musn't return! */ | 
| 214 |  | } | 
| 215 |  |  | 
| 220 |  | trace_contrib(RAY *r) | 
| 221 |  | { | 
| 222 |  | MODCONT *mp; | 
| 223 | + | double  bval; | 
| 224 |  | int     bn; | 
| 225 |  | RREAL   contr[3]; | 
| 226 |  |  | 
| 227 | < | if (r->ro == NULL || !inset(traset, r->ro->omod)) | 
| 227 | > | if (r->ro == NULL || r->ro->omod == OVOID) | 
| 228 |  | return; | 
| 229 | + | /* shadow ray not on source? */ | 
| 230 | + | if (r->rsrc >= 0 && source[r->rsrc].so != r->ro) | 
| 231 | + | return; | 
| 232 |  |  | 
| 233 |  | mp = (MODCONT *)lu_find(&modconttab,objptr(r->ro->omod)->oname)->data; | 
| 234 |  |  | 
| 235 | < | if (mp == NULL) | 
| 236 | < | error(CONSISTENCY, "unexpected modifier in trace_contrib()"); | 
| 235 | > | if (mp == NULL)                         /* not in our list? */ | 
| 236 | > | return; | 
| 237 |  |  | 
| 238 | < | worldfunc(RCCONTEXT, r);                /* get bin number */ | 
| 239 | < | bn = (int)(evalue(mp->binv) + .5); | 
| 240 | < | if ((bn < 0) | (bn >= mp->nbins)) { | 
| 241 | < | error(WARNING, "bad bin number (ignored)"); | 
| 238 | > | worldfunc(RCCONTEXT, r);                /* else set context */ | 
| 239 | > | set_eparams((char *)mp->params); | 
| 240 | > | if ((bval = evalue(mp->binv)) <= -.5)   /* and get bin number */ | 
| 241 | > | return;                         /* silently ignore negatives */ | 
| 242 | > | if ((bn = (int)(bval + .5)) >= mp->nbins) { | 
| 243 | > | sprintf(errmsg, "bad bin number (%d ignored)", bn); | 
| 244 | > | error(WARNING, errmsg); | 
| 245 |  | return; | 
| 246 |  | } | 
| 247 | < | raycontrib(contr, r, PRIMARY); | 
| 247 | > | raycontrib(contr, r, PRIMARY);          /* compute coefficient */ | 
| 248 |  | if (contrib) | 
| 249 | < | multcolor(contr, r->rcol); | 
| 249 | > | multcolor(contr, r->rcol);      /* -> contribution */ | 
| 250 |  | addcolor(mp->cbin[bn], contr); | 
| 251 |  | } | 
| 252 |  |  | 
| 253 |  |  | 
| 254 | + | /* Evaluate irradiance contributions */ | 
| 255 |  | static void | 
| 256 | < | rayirrad(                       /* compute irradiance rather than radiance */ | 
| 291 | < | RAY *r | 
| 292 | < | ) | 
| 256 | > | eval_irrad(FVECT org, FVECT dir) | 
| 257 |  | { | 
| 258 | < | r->rot = 1e-5;                  /* pretend we hit surface */ | 
| 259 | < | VSUM(r->rop, r->rorg, r->rdir, r->rot); | 
| 260 | < | r->ron[0] = -r->rdir[0]; | 
| 261 | < | r->ron[1] = -r->rdir[1]; | 
| 262 | < | r->ron[2] = -r->rdir[2]; | 
| 263 | < | r->rod = 1.0; | 
| 264 | < | /* compute result */ | 
| 265 | < | r->revf = raytrace; | 
| 266 | < | (*ofun[Lamb.otype].funp)(&Lamb, r); | 
| 267 | < | r->revf = rayirrad; | 
| 258 | > | RAY     thisray; | 
| 259 | > |  | 
| 260 | > | VSUM(thisray.rorg, org, dir, 1.1e-4); | 
| 261 | > | thisray.rdir[0] = -dir[0]; | 
| 262 | > | thisray.rdir[1] = -dir[1]; | 
| 263 | > | thisray.rdir[2] = -dir[2]; | 
| 264 | > | thisray.rmax = 0.0; | 
| 265 | > | rayorigin(&thisray, PRIMARY, NULL, NULL); | 
| 266 | > | /* pretend we hit surface */ | 
| 267 | > | thisray.rt = thisray.rot = 1e-5; | 
| 268 | > | thisray.rod = 1.0; | 
| 269 | > | VCOPY(thisray.ron, dir); | 
| 270 | > | VSUM(thisray.rop, org, dir, 1e-4); | 
| 271 | > | samplendx++;                    /* compute result */ | 
| 272 | > | (*ofun[Lamb.otype].funp)(&Lamb, &thisray); | 
| 273 |  | } | 
| 274 |  |  | 
| 275 |  |  | 
| 276 | < | /* Evaluate ray contributions */ | 
| 276 | > | /* Evaluate radiance contributions */ | 
| 277 |  | static void | 
| 278 | < | eval_ray(FVECT  org, FVECT  dir, double dmax) | 
| 278 | > | eval_rad(FVECT org, FVECT dir, double dmax) | 
| 279 |  | { | 
| 280 |  | RAY     thisray; | 
| 281 |  | /* set up ray */ | 
| 282 | + | VCOPY(thisray.rorg, org); | 
| 283 | + | VCOPY(thisray.rdir, dir); | 
| 284 | + | thisray.rmax = dmax; | 
| 285 |  | rayorigin(&thisray, PRIMARY, NULL, NULL); | 
| 314 | – | if (imm_irrad) { | 
| 315 | – | VSUM(thisray.rorg, org, dir, 1.1e-4); | 
| 316 | – | thisray.rdir[0] = -dir[0]; | 
| 317 | – | thisray.rdir[1] = -dir[1]; | 
| 318 | – | thisray.rdir[2] = -dir[2]; | 
| 319 | – | thisray.rmax = 0.0; | 
| 320 | – | thisray.revf = rayirrad; | 
| 321 | – | } else { | 
| 322 | – | VCOPY(thisray.rorg, org); | 
| 323 | – | VCOPY(thisray.rdir, dir); | 
| 324 | – | thisray.rmax = dmax; | 
| 325 | – | } | 
| 286 |  | samplendx++;                    /* call ray evaluation */ | 
| 287 |  | rayvalue(&thisray); | 
| 288 |  | } | 
| 316 |  | static int      ignore_warning_given = 0; | 
| 317 |  | FVECT           orig, direc; | 
| 318 |  | double          d; | 
| 319 | < | /* initialize & fork */ | 
| 319 | > | /* initialize (& fork more of us) */ | 
| 320 |  | rcinit(); | 
| 321 |  | /* load rays from stdin & process */ | 
| 322 |  | #ifdef getc_unlocked | 
| 323 | < | flockfile(stdin);               /* avoid lock/unlock overhead */ | 
| 323 | > | flockfile(stdin);               /* avoid mutex overhead */ | 
| 324 |  | #endif | 
| 325 |  | while (getvec(orig) == 0 && getvec(direc) == 0) { | 
| 326 |  | d = normalize(direc); | 
| 327 | < | if ((d == 0.0) & (accumulate != 1)) { | 
| 327 | > | if (nchild != -1 && (d == 0.0) & (accumulate == 0)) { | 
| 328 |  | if (!ignore_warning_given++) | 
| 329 |  | error(WARNING, | 
| 330 |  | "dummy ray(s) ignored during accumulation\n"); | 
| 334 |  | lastray = lastdone = 0; | 
| 335 |  | ++lastray; | 
| 336 |  | if (d == 0.0) {                         /* zero ==> flush */ | 
| 337 | < | if ((yres <= 0) | (xres <= 0)) | 
| 338 | < | waitflush = 1;          /* flush right after */ | 
| 339 | < | } else {                                /* else compute */ | 
| 340 | < | eval_ray(orig, direc, lim_dist ? d : 0.0); | 
| 337 | > | if ((yres <= 0) | (xres <= 1)) | 
| 338 | > | waitflush = 1;          /* flush after */ | 
| 339 | > | if (nchild == -1) | 
| 340 | > | account = 1; | 
| 341 | > | } else if (imm_irrad) {                 /* else compute */ | 
| 342 | > | eval_irrad(orig, direc); | 
| 343 | > | } else { | 
| 344 | > | eval_rad(orig, direc, lim_dist ? d : 0.0); | 
| 345 |  | } | 
| 346 |  | done_contrib();         /* accumulate/output */ | 
| 347 |  | ++lastdone; | 
| 348 |  | if (raysleft && !--raysleft) | 
| 349 |  | break;          /* preemptive EOI */ | 
| 350 |  | } | 
| 351 | < | if (accumulate <= 0 || account < accumulate) { | 
| 351 | > | if (nchild != -1 && (accumulate <= 0) | (account < accumulate)) { | 
| 352 |  | if (account < accumulate) { | 
| 353 |  | error(WARNING, "partial accumulation in final record"); | 
| 354 |  | accumulate -= account; | 
| 356 |  | account = 1;            /* output accumulated totals */ | 
| 357 |  | done_contrib(); | 
| 358 |  | } | 
| 359 | + | lu_done(&ofiletab);             /* close output files */ | 
| 360 |  | if (raysleft) | 
| 361 |  | error(USER, "unexpected EOF on input"); | 
| 397 | – | lu_done(&ofiletab);             /* close output files */ | 
| 362 |  | } |