static AMBHEMI * samp_hemi( /* sample indirect hemisphere */ COLOR rcol, RAY *r, double wt ) { AMBHEMI *hp; double d; int n, i, j; /* insignificance check */ if (bright(rcol) <= FTINY) return(NULL); /* set number of divisions */ if (ambacc <= FTINY && wt > (d = 0.8*intens(rcol)*r->rweight/(ambdiv*minweight))) wt = d; /* avoid ray termination */ n = sqrt(ambdiv * wt) + 0.5; i = 1 + 5*(ambacc > FTINY); /* minimum number of samples */ if (n < i) n = i; /* allocate sampling array */ hp = (AMBHEMI *)malloc(sizeof(AMBHEMI) + sizeof(AMBSAMP)*(n*n - 1)); if (hp == NULL) error(SYSTEM, "out of memory in samp_hemi"); hp->rp = r; hp->ns = n; hp->acol[RED] = hp->acol[GRN] = hp->acol[BLU] = 0.0; memset(hp->sa, 0, sizeof(AMBSAMP)*n*n); hp->sampOK = 0; /* assign coefficient */ copycolor(hp->acoef, rcol); d = 1.0/(n*n); scalecolor(hp->acoef, d); /* make tangent plane axes */ if (!getperpendicular(hp->ux, r->ron, 1)) error(CONSISTENCY, "bad ray direction in samp_hemi"); VCROSS(hp->uy, r->ron, hp->ux); /* sample divisions */ for (i = hp->ns; i--; ) for (j = hp->ns; j--; ) hp->sampOK += ambsample(hp, i, j, 0); copycolor(rcol, hp->acol); if (!hp->sampOK) { /* utter failure? */ free(hp); return(NULL); } if (hp->sampOK < hp->ns*hp->ns) { hp->sampOK *= -1; /* soft failure */ return(hp); } if (hp->sampOK < 64) return(hp); /* insufficient for super-sampling */ n = ambssamp*wt + 0.5; if (n > 8) { /* perform super-sampling? */ ambsupersamp(hp, n); copycolor(rcol, hp->acol); } return(hp); /* all is well */ }
/* Get ray contribution from previous file */ static int get_contrib(DCOLOR cnt, FILE *finp) { COLOR fv; COLR cv; switch (outfmt) { case 'a': return(fscanf(finp,"%lf %lf %lf",&cnt[0],&cnt[1],&cnt[2]) == 3); case 'f': if (fread(fv, sizeof(fv[0]), 3, finp) != 3) return(0); copycolor(cnt, fv); return(1); case 'd': return(fread(cnt, sizeof(cnt[0]), 3, finp) == 3); case 'c': if (fread(cv, sizeof(cv), 1, finp) != 1) return(0); colr_color(fv, cv); copycolor(cnt, fv); return(1); default: error(INTERNAL, "botched output format"); } return(0); /* pro forma return */ }
/* write out matrix to file (precede by resolution string if picture) */ int cm_write(const CMATRIX *cm, int dtype, FILE *fp) { static const char tabEOL[2] = {'\t','\n'}; const COLORV *mp = cm->cmem; int r, c; switch (dtype) { case DTascii: for (r = 0; r < cm->nrows; r++) for (c = 0; c < cm->ncols; c++, mp += 3) fprintf(fp, "%.6e %.6e %.6e%c", mp[0], mp[1], mp[2], tabEOL[c >= cm->ncols-1]); break; case DTfloat: case DTdouble: if (sizeof(COLOR) == cm_elem_size[dtype]) { r = cm->ncols*cm->nrows; while (r > 0) { c = putbinary(mp, sizeof(COLOR), r, fp); if (c <= 0) return(0); mp += 3*c; r -= c; } } else if (dtype == DTdouble) { double dc[3]; r = cm->ncols*cm->nrows; while (r--) { copycolor(dc, mp); if (putbinary(dc, sizeof(double), 3, fp) != 3) return(0); mp += 3; } } else /* dtype == DTfloat */ { float fc[3]; r = cm->ncols*cm->nrows; while (r--) { copycolor(fc, mp); if (putbinary(fc, sizeof(float), 3, fp) != 3) return(0); mp += 3; } } break; case DTrgbe: case DTxyze: fprtresolu(cm->ncols, cm->nrows, fp); for (r = 0; r < cm->nrows; r++, mp += 3*cm->ncols) if (fwritescan((COLOR *)mp, cm->ncols, fp) < 0) return(0); break; default: fputs("Unsupported data type in cm_write()!\n", stderr); return(0); } return(fflush(fp) == 0); }
extern int raymixture( /* mix modifiers */ RAY *r, OBJECT fore, OBJECT back, double coef ) { RAY fr, br; int foremat, backmat; int i; /* bound coefficient */ if (coef > 1.0) coef = 1.0; else if (coef < 0.0) coef = 0.0; /* compute foreground and background */ foremat = backmat = 0; /* foreground */ fr = *r; if (coef > FTINY) { fr.rweight *= coef; scalecolor(fr.rcoef, coef); foremat = rayshade(&fr, fore); } /* background */ br = *r; if (coef < 1.0-FTINY) { br.rweight *= 1.0-coef; scalecolor(br.rcoef, 1.0-coef); backmat = rayshade(&br, back); } /* check for transparency */ if (backmat ^ foremat) { if (backmat && coef > FTINY) raytrans(&fr); else if (foremat && coef < 1.0-FTINY) raytrans(&br); } /* mix perturbations */ for (i = 0; i < 3; i++) r->pert[i] = coef*fr.pert[i] + (1.0-coef)*br.pert[i]; /* mix pattern colors */ scalecolor(fr.pcol, coef); scalecolor(br.pcol, 1.0-coef); copycolor(r->pcol, fr.pcol); addcolor(r->pcol, br.pcol); /* return value tells if material */ if (!foremat & !backmat) return(0); /* mix returned ray values */ scalecolor(fr.rcol, coef); scalecolor(br.rcol, 1.0-coef); copycolor(r->rcol, fr.rcol); addcolor(r->rcol, br.rcol); r->rt = bright(fr.rcol) > bright(br.rcol) ? fr.rt : br.rt; return(1); }
static void dirashik( /* compute source contribution */ COLOR cval, /* returned coefficient */ void *nnp, /* material data */ FVECT ldir, /* light source direction */ double omega /* light source size */ ) { ASHIKDAT *np = nnp; double ldot; double dtmp, dtmp1, dtmp2; FVECT h; COLOR ctmp; setcolor(cval, 0.0, 0.0, 0.0); ldot = DOT(np->pnorm, ldir); if (ldot < 0.0) return; /* wrong side */ /* * Compute and add diffuse reflected component to returned * color. */ copycolor(ctmp, np->mcolor); dtmp = ldot * omega * (1.0/PI) * (1. - schlick_fres(ldot)); scalecolor(ctmp, dtmp); addcolor(cval, ctmp); if ((np->specfl & (SPA_REFL|SPA_BADU)) != SPA_REFL) return; /* * Compute specular reflection coefficient */ /* half vector */ VSUB(h, ldir, np->rp->rdir); normalize(h); /* ellipse */ dtmp1 = DOT(np->u, h); dtmp1 *= dtmp1 * np->u_power; dtmp2 = DOT(np->v, h); dtmp2 *= dtmp2 * np->v_power; /* Ashikhmin-Shirley model*/ dtmp = DOT(np->pnorm, h); dtmp = pow(dtmp, (dtmp1+dtmp2)/(1.-dtmp*dtmp)); dtmp *= sqrt((np->u_power+1.)*(np->v_power+1.)); dtmp /= 8.*PI * DOT(ldir,h) * MAX(ldot,np->pdot); /* worth using? */ if (dtmp > FTINY) { copycolor(ctmp, np->scolor); dtmp *= ldot * omega; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } }
static void picdebug(void) /* put out debugging picture */ { static COLOR blkcol = BLKCOLOR; COLOR *scan; int y, i; register int x, rg; if (fseek(stdin, 0L, 0) == EOF) { fprintf(stderr, "%s: cannot seek on input picture\n", progname); exit(1); } getheader(stdin, NULL, NULL); /* skip input header */ fgetresolu(&xmax, &ymax, stdin); /* allocate scanline */ scan = (COLOR *)malloc(xmax*sizeof(COLOR)); if (scan == NULL) { perror(progname); exit(1); } /* finish debug header */ fputformat(COLRFMT, debugfp); putc('\n', debugfp); fprtresolu(xmax, ymax, debugfp); /* write debug picture */ for (y = ymax-1; y >= 0; y--) { if (freadscan(scan, xmax, stdin) < 0) { fprintf(stderr, "%s: error rereading input picture\n", progname); exit(1); } for (x = 0; x < xmax; x++) { rg = chartndx(x, y, &i); if (rg == RG_CENT) { if (!(1L<<i & gmtflags) || (x+y)&07) { copycolor(scan[x], mbRGB[i]); clipgamut(scan[x], bright(scan[x]), CGAMUT, colmin, colmax); } else copycolor(scan[x], blkcol); } else if (rg == RG_CORR) cvtcolor(scan[x], scan[x]); else if (rg != RG_ORIG) copycolor(scan[x], blkcol); } if (fwritescan(scan, xmax, debugfp) < 0) { fprintf(stderr, "%s: error writing debugging picture\n", progname); exit(1); } } /* clean up */ fclose(debugfp); free((void *)scan); }
int freadscan( /* read in a scanline */ COLOR *scanline, int len, FILE *fp ) { COLR *clrscan; if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) return(-1); if (freadcolrs(clrscan, len, fp) < 0) return(-1); /* convert scanline */ colr_color(scanline[0], clrscan[0]); while (--len > 0) { scanline++; clrscan++; if (clrscan[0][GRN] == clrscan[-1][GRN] && (clrscan[0][RED] == clrscan[-1][RED]) & (clrscan[0][BLU] == clrscan[-1][BLU]) & (clrscan[0][EXP] == clrscan[-1][EXP])) copycolor(scanline[0], scanline[-1]); else colr_color(scanline[0], clrscan[0]); } return(0); }
int m_aniso( /* anisotropic material */ register OBJREC *o ) { register MATREC *m; /* check arguments */ if (o->oargs.nfargs < (o->otype == MAT_TRANS2 ? 8 : 6)) objerror(o, USER, "bad # of real arguments"); /* allocate/insert material */ m = newmaterial(o->oname); /* assign parameters */ setcolor(m->u.m.ambdiff, o->oargs.farg[0], o->oargs.farg[1], o->oargs.farg[2]); if ((m->type = o->otype) == MAT_METAL2) copycolor(m->u.m.specular, m->u.m.ambdiff); else setcolor(m->u.m.specular, 1., 1., 1.); scalecolor(m->u.m.specular, o->oargs.farg[3]); scalecolor(m->u.m.ambdiff, 1.-o->oargs.farg[3]); if (m->type == MAT_TRANS2) { scalecolor(m->u.m.specular, 1.-o->oargs.farg[6]); scalecolor(m->u.m.ambdiff, 1.-o->oargs.farg[6]); } if (o->oargs.farg[4]*o->oargs.farg[5] <= FTINY*FTINY) m->u.m.specexp = MAXSPECEXP; else m->u.m.specexp = 2./(o->oargs.farg[4]*o->oargs.farg[5]); if (m->u.m.specexp > MAXSPECEXP) m->u.m.specexp = MAXSPECEXP; return(0); }
extern void extambient( /* extrapolate value at pv, nv */ COLOR cr, AMBVAL *ap, FVECT pv, FVECT nv ) { FVECT v1; int i; double d; d = 1.0; /* zeroeth order */ /* gradient due to translation */ for (i = 0; i < 3; i++) d += ap->gpos[i]*(pv[i]-ap->pos[i]); /* gradient due to rotation */ VCROSS(v1, ap->dir, nv); d += DOT(ap->gdir, v1); if (d <= 0.0) { setcolor(cr, 0.0, 0.0, 0.0); return; } copycolor(cr, ap->val); scalecolor(cr, d); }
/* Put out ray contribution to file */ static void put_contrib(const DCOLOR cnt, FILE *fout) { double sf = 1; COLOR fv; COLR cv; if (accumulate > 1) sf = 1./(double)accumulate; switch (outfmt) { case 'a': if (accumulate > 1) fprintf(fout, "%.6e\t%.6e\t%.6e\t", sf*cnt[0], sf*cnt[1], sf*cnt[2]); else fprintf(fout, "%.6e\t%.6e\t%.6e\t", cnt[0], cnt[1], cnt[2]); break; case 'f': if (accumulate > 1) { copycolor(fv, cnt); scalecolor(fv, sf); } else copycolor(fv, cnt); fwrite(fv, sizeof(float), 3, fout); break; case 'd': if (accumulate > 1) { DCOLOR dv; copycolor(dv, cnt); scalecolor(dv, sf); fwrite(dv, sizeof(double), 3, fout); } else fwrite(cnt, sizeof(double), 3, fout); break; case 'c': if (accumulate > 1) setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]); else setcolr(cv, cnt[0], cnt[1], cnt[2]); fwrite(cv, sizeof(cv), 1, fout); break; default: error(INTERNAL, "botched output format"); } }
void pcopy( /* copy paint node p1 into p2 */ PNODE *p1, PNODE *p2 ) { copycolor(p2->v, p1->v); p2->x = p1->x; p2->y = p1->y; }
/* Multiply two matrices (or a matrix and a vector) and allocate the result */ CMATRIX * cm_multiply(const CMATRIX *cm1, const CMATRIX *cm2) { char *rowcheck=NULL, *colcheck=NULL; CMATRIX *cmr; int dr, dc, i; if ((cm1->ncols <= 0) | (cm1->ncols != cm2->nrows)) error(INTERNAL, "matrix dimension mismatch in cm_multiply()"); cmr = cm_alloc(cm1->nrows, cm2->ncols); if (cmr == NULL) return(NULL); /* optimization: check for zero rows & cols */ if (((cm1->nrows > 5) | (cm2->ncols > 5)) & (cm1->ncols > 5)) { static const COLOR czero; rowcheck = (char *)calloc(cmr->nrows, 1); for (dr = cm1->nrows*(rowcheck != NULL); dr--; ) for (dc = cm1->ncols; dc--; ) if (memcmp(cm_lval(cm1,dr,dc), czero, sizeof(COLOR))) { rowcheck[dr] = 1; break; } colcheck = (char *)calloc(cmr->ncols, 1); for (dc = cm2->ncols*(colcheck != NULL); dc--; ) for (dr = cm2->nrows; dr--; ) if (memcmp(cm_lval(cm2,dr,dc), czero, sizeof(COLOR))) { colcheck[dc] = 1; break; } } for (dr = 0; dr < cmr->nrows; dr++) for (dc = 0; dc < cmr->ncols; dc++) { COLORV *dp = cm_lval(cmr,dr,dc); double res[3]; dp[0] = dp[1] = dp[2] = 0; if (rowcheck != NULL && !rowcheck[dr]) continue; if (colcheck != NULL && !colcheck[dc]) continue; res[0] = res[1] = res[2] = 0; for (i = 0; i < cm1->ncols; i++) { const COLORV *cp1 = cm_lval(cm1,dr,i); const COLORV *cp2 = cm_lval(cm2,i,dc); res[0] += (double)cp1[0] * cp2[0]; res[1] += (double)cp1[1] * cp2[1]; res[2] += (double)cp1[2] * cp2[2]; } copycolor(dp, res); } if (rowcheck != NULL) free(rowcheck); if (colcheck != NULL) free(colcheck); return(cmr); }
extern void raytrans( /* transmit ray as is */ RAY *r ) { RAY tr; if (rayorigin(&tr, TRANS, r, NULL) == 0) { VCOPY(tr.rdir, r->rdir); rayvalue(&tr); copycolor(r->rcol, tr.rcol); r->rt = r->rot + tr.rt; } }
static double greypoint( /* compute gamut mapping grey target */ COLOR col ) { COLOR gryc; int i; /* improves saturated color rendering */ copycolor(gryc, col); for (i = 3; i--; ) if (gryc[i] > 1) gryc[i] = 1; else if (gryc[i] < 0) gryc[i] = 0; return(bright(gryc)); }
static void vips_rad2float_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width ) { COLR *inp = (COLR *) in[0]; COLOR *outbuf = (COLOR *) out; colr_color(outbuf[0], inp[0]); while (--width > 0) { outbuf++; inp++; if (inp[0][RED] == inp[-1][RED] && inp[0][GRN] == inp[-1][GRN] && inp[0][BLU] == inp[-1][BLU] && inp[0][EXP] == inp[-1][EXP]) copycolor(outbuf[0], outbuf[-1]); else colr_color(outbuf[0], inp[0]); } }
int waitrays(void) /* finish up pending rays */ { int nwaited = 0; int rval; RAY raydone; if (!ray_pnprocs) /* immediate mode? */ return(0); while ((rval = ray_presult(&raydone, 0)) > 0) { PNODE *p = (PNODE *)raydone.rno; copycolor(p->v, raydone.rcol); scalecolor(p->v, exposure); recolor(p); nwaited++; } if (rval < 0) return(-1); return(nwaited); }
extern double makeambient( /* make a new ambient value for storage */ COLOR acol, RAY *r, FVECT rn, int al ) { AMBVAL amb; FVECT gp, gd; int i; amb.weight = 1.0; /* compute weight */ for (i = al; i-- > 0; ) amb.weight *= AVGREFL; if (r->rweight < 0.1*amb.weight) /* heuristic override */ amb.weight = 1.25*r->rweight; setcolor(acol, AVGREFL, AVGREFL, AVGREFL); /* compute ambient */ amb.rad = doambient(acol, r, amb.weight, gp, gd); if (amb.rad <= FTINY) { setcolor(acol, 0.0, 0.0, 0.0); return(0.0); } scalecolor(acol, 1./AVGREFL); /* undo assumed reflectance */ /* store value */ VCOPY(amb.pos, r->rop); VCOPY(amb.dir, r->ron); amb.lvl = al; copycolor(amb.val, acol); VCOPY(amb.gpos, gp); VCOPY(amb.gdir, gd); /* insert into tree */ avsave(&amb); /* and save to file */ if (rn != r->ron) extambient(acol, &amb, r->rop, rn); /* texture */ return(amb.rad); }
static void starpoint( /* pixel is on the star's point */ COLOR fcol, int x, int y, register HOTPIX *hp ) { COLOR ctmp; double d2; d2 = (double)(x - hp->x)*(x - hp->x) + (double)(y - hp->y)*(y - hp->y); if (d2 > sprdfact) { d2 = sprdfact / d2; if (d2 < FTINY) return; copycolor(ctmp, hp->val); scalecolor(ctmp, d2); addcolor(fcol, ctmp); } else if (d2 > FTINY) { addcolor(fcol, hp->val); } }
static inline void split_patch(pdf_tensorpatch *s0, pdf_tensorpatch *s1, const pdf_tensorpatch *p) { split_curve_s(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4); split_curve_s(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4); split_curve_s(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4); split_curve_s(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4); copycolor(s0->color[0], p->color[0]); midcolor(s0->color[1], p->color[0], p->color[1]); midcolor(s0->color[2], p->color[2], p->color[3]); copycolor(s0->color[3], p->color[3]); copycolor(s1->color[0], s0->color[1]); copycolor(s1->color[1], p->color[1]); copycolor(s1->color[2], p->color[2]); copycolor(s1->color[3], s0->color[2]); }
extern void dogauss( /* gaussian filter */ COLOR csum, int xcent, int ycent, int c, int r ) { double dy, dx, weight, wsum; COLOR ctmp; int y; register int x, offs; register COLOR *scan; wsum = FTINY; setcolor(csum, 0.0, 0.0, 0.0); for (y = ycent-yrad; y <= ycent+yrad; y++) { if (y < 0) continue; if (y >= yres) break; dy = (y_r*(y+.5) - (r+.5))/rad; scan = scanin[y%barsize]; for (x = xcent-xrad; x <= xcent+xrad; x++) { offs = x < 0 ? xres : x >= xres ? -xres : 0; if (offs && !wrapfilt) continue; dx = (x_c*(x+.5) - (c+.5))/rad; weight = lookgauss(dx*dx + dy*dy); wsum += weight; copycolor(ctmp, scan[x+offs]); scalecolor(ctmp, weight); addcolor(csum, ctmp); } } weight = 1.0/wsum; scalecolor(csum, weight); }
extern void pass1scan( /* process first pass scanline */ register COLOR *scan, int y ) { double cbrt; register int x; register HOTPIX *hp; for (x = 0; x < xres; x++) { cbrt = (*ourbright)(scan[x]); if (cbrt <= 0) continue; if (avghot || cbrt < hotlvl) { avgbrt += cbrt; npix++; } if (npts && cbrt >= hotlvl) { hp = (HOTPIX *)malloc(sizeof(HOTPIX)); if (hp == NULL) { fprintf(stderr, "%s: out of memory\n", progname); quit(1); } copycolor(hp->val, scan[x]); hp->x = x; hp->y = y; hp->slope = tan(PI*(0.5-(random()%npts+0.5)/npts)); hp->next = head; head = hp; } } }
static inline void split_stripe(pdf_tensorpatch *s0, pdf_tensorpatch *s1, const pdf_tensorpatch *p) { split_curve_s(p->pole[0], s0->pole[0], s1->pole[0], 1); split_curve_s(p->pole[1], s0->pole[1], s1->pole[1], 1); split_curve_s(p->pole[2], s0->pole[2], s1->pole[2], 1); split_curve_s(p->pole[3], s0->pole[3], s1->pole[3], 1); copycolor(s0->color[0], p->color[0]); copycolor(s0->color[1], p->color[1]); midcolor(s0->color[2], p->color[1], p->color[2]); midcolor(s0->color[3], p->color[0], p->color[3]); copycolor(s1->color[0], s0->color[3]); copycolor(s1->color[1], s0->color[2]); copycolor(s1->color[2], p->color[2]); copycolor(s1->color[3], p->color[3]); }
static void sumans( /* sum input pixel to output */ int px, int py, int rcent, int ccent, double m ) { double dy2, dx; COLOR pval, ctmp; int ksiz, r, offs; double pc, pr, norm; register int i, c; register COLOR *scan; /* * This normalization method fails at the picture borders because * a different number of input pixels contribute there. */ scan = scanin[py%barsize] + (px < 0 ? xres : px >= xres ? -xres : 0); copycolor(pval, scan[px]); pc = x_c*(px+.5); pr = y_r*(py+.5); ksiz = CHECKRAD*m*rad + 1; if (ksiz > orad) ksiz = orad; /* compute normalization */ norm = 0.0; i = 0; for (r = rcent-ksiz; r <= rcent+ksiz; r++) { if (r < 0) continue; if (r >= nrows) break; dy2 = (pr - (r+.5))/(m*rad); dy2 *= dy2; for (c = ccent-ksiz; c <= ccent+ksiz; c++) { if (!wrapfilt) { if (c < 0) continue; if (c >= ncols) break; } dx = (pc - (c+.5))/(m*rad); norm += warr[i++] = lookgauss(dx*dx + dy2); } } norm = 1.0/norm; if (x_c < 1.0) norm *= x_c; if (y_r < 1.0) norm *= y_r; /* sum pixels */ i = 0; for (r = rcent-ksiz; r <= rcent+ksiz; r++) { if (r < 0) continue; if (r >= nrows) break; scan = scoutbar[r%obarsize]; for (c = ccent-ksiz; c <= ccent+ksiz; c++) { offs = c < 0 ? ncols : c >= ncols ? -ncols : 0; if (offs && !wrapfilt) continue; copycolor(ctmp, pval); dx = norm*warr[i++]; scalecolor(ctmp, dx); addcolor(scan[c+offs], ctmp); } } }
static int ambsample( /* initial ambient division sample */ AMBHEMI *hp, int i, int j, int n ) { AMBSAMP *ap = &ambsam(hp,i,j); RAY ar; int hlist[3], ii; double spt[2], zd; /* generate hemispherical sample */ /* ambient coefficient for weight */ if (ambacc > FTINY) setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); else copycolor(ar.rcoef, hp->acoef); if (rayorigin(&ar, AMBIENT, hp->rp, ar.rcoef) < 0) return(0); if (ambacc > FTINY) { multcolor(ar.rcoef, hp->acoef); scalecolor(ar.rcoef, 1./AVGREFL); } hlist[0] = hp->rp->rno; hlist[1] = j; hlist[2] = i; multisamp(spt, 2, urand(ilhash(hlist,3)+n)); resample: SDsquare2disk(spt, (j+spt[1])/hp->ns, (i+spt[0])/hp->ns); zd = sqrt(1. - spt[0]*spt[0] - spt[1]*spt[1]); for (ii = 3; ii--; ) ar.rdir[ii] = spt[0]*hp->ux[ii] + spt[1]*hp->uy[ii] + zd*hp->rp->ron[ii]; checknorm(ar.rdir); /* avoid coincident samples */ if (!n && ambcollision(hp, i, j, ar.rdir)) { spt[0] = frandom(); spt[1] = frandom(); goto resample; /* reject this sample */ } dimlist[ndims++] = AI(hp,i,j) + 90171; rayvalue(&ar); /* evaluate ray */ ndims--; zd = raydistance(&ar); if (zd <= FTINY) return(0); /* should never happen */ multcolor(ar.rcol, ar.rcoef); /* apply coefficient */ if (zd*ap->d < 1.0) /* new/closer distance? */ ap->d = 1.0/zd; if (!n) { /* record first vertex & value */ if (zd > 10.0*thescene.cusize + 1000.) zd = 10.0*thescene.cusize + 1000.; VSUM(ap->p, ar.rorg, ar.rdir, zd); copycolor(ap->v, ar.rcol); } else { /* else update recorded value */ hp->acol[RED] -= colval(ap->v,RED); hp->acol[GRN] -= colval(ap->v,GRN); hp->acol[BLU] -= colval(ap->v,BLU); zd = 1.0/(double)(n+1); scalecolor(ar.rcol, zd); zd *= (double)n; scalecolor(ap->v, zd); addcolor(ap->v, ar.rcol); } addcolor(hp->acol, ap->v); /* add to our sum */ return(1); }
extern void direct( /* add direct component */ RAY *r, /* ray that hit surface */ srcdirf_t *f, /* direct component coefficient function */ void *p /* data for f */ ) { register int sn; register CONTRIB *scp; SRCINDEX si; int nshadcheck, ncnts; int nhits; double prob, ourthresh, hwt; RAY sr; /* NOTE: srccnt and cntord global so no recursion */ if (nsources <= 0) return; /* no sources?! */ /* potential contributions */ initsrcindex(&si); for (sn = 0; srcray(&sr, r, &si); sn++) { if (sn >= maxcntr) { maxcntr = sn + MAXSPART; srccnt = (CONTRIB *)realloc((void *)srccnt, maxcntr*sizeof(CONTRIB)); cntord = (CNTPTR *)realloc((void *)cntord, maxcntr*sizeof(CNTPTR)); if ((srccnt == NULL) | (cntord == NULL)) error(SYSTEM, "out of memory in direct"); } cntord[sn].sndx = sn; scp = srccnt + sn; scp->sno = sr.rsrc; /* compute coefficient */ (*f)(scp->coef, p, sr.rdir, si.dom); cntord[sn].brt = intens(scp->coef); if (cntord[sn].brt <= 0.0) continue; #if SHADCACHE /* check shadow cache */ if (si.np == 1 && srcblocked(&sr)) { cntord[sn].brt = 0.0; continue; } #endif VCOPY(scp->dir, sr.rdir); copycolor(sr.rcoef, scp->coef); /* compute potential */ sr.revf = srcvalue; rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); copycolor(scp->val, sr.rcol); cntord[sn].brt = bright(sr.rcol); } /* sort contributions */ qsort(cntord, sn, sizeof(CNTPTR), cntcmp); { /* find last */ register int l, m; ncnts = l = sn; sn = 0; while ((m = (sn + ncnts) >> 1) != l) { if (cntord[m].brt > 0.0) sn = m; else ncnts = m; l = m; } } if (ncnts == 0) return; /* no contributions! */ /* accumulate tail */ for (sn = ncnts-1; sn > 0; sn--) cntord[sn-1].brt += cntord[sn].brt; /* compute number to check */ nshadcheck = pow((double)ncnts, shadcert) + .5; /* modify threshold */ ourthresh = shadthresh / r->rweight; /* test for shadows */ for (nhits = 0, hwt = 0.0, sn = 0; sn < ncnts; hwt += (double)source[scp->sno].nhits / (double)source[scp->sno].ntests, sn++) { /* check threshold */ if ((sn+nshadcheck>=ncnts ? cntord[sn].brt : cntord[sn].brt-cntord[sn+nshadcheck].brt) < ourthresh*bright(r->rcol)) break; scp = srccnt + cntord[sn].sndx; /* test for hit */ rayorigin(&sr, SHADOW, r, NULL); copycolor(sr.rcoef, scp->coef); VCOPY(sr.rdir, scp->dir); sr.rsrc = scp->sno; /* keep statistics */ if (source[scp->sno].ntests++ > 0xfffffff0) { source[scp->sno].ntests >>= 1; source[scp->sno].nhits >>= 1; } if (localhit(&sr, &thescene) && ( sr.ro != source[scp->sno].so || source[scp->sno].sflags & SFOLLOW )) { /* follow entire path */ raycont(&sr); if (trace != NULL) (*trace)(&sr); /* trace execution */ if (bright(sr.rcol) <= FTINY) { #if SHADCACHE if ((scp <= srccnt || scp[-1].sno != scp->sno) && (scp >= srccnt+ncnts-1 || scp[1].sno != scp->sno)) srcblocker(&sr); #endif continue; /* missed! */ } rayparticipate(&sr); multcolor(sr.rcol, sr.rcoef); copycolor(scp->val, sr.rcol); } else if (trace != NULL && (source[scp->sno].sflags & (SDISTANT|SVIRTUAL|SFOLLOW)) == (SDISTANT|SFOLLOW) && sourcehit(&sr) && rayshade(&sr, sr.ro->omod)) { (*trace)(&sr); /* trace execution */ /* skip call to rayparticipate() & scp->val update */ } /* add contribution if hit */ addcolor(r->rcol, scp->val); nhits++; source[scp->sno].nhits++; }
int m_dielectric( /* color a ray which hit a dielectric interface */ OBJREC *m, RAY *r ) { double cos1, cos2, nratio; COLOR ctrans; COLOR talb; int hastexture; int flatsurface; double refl, trans; FVECT dnorm; double d1, d2; RAY p; int i; /* PMAP: skip refracted shadow or ambient ray if accounted for in photon map */ if (shadowRayInPmap(r) || ambRayInPmap(r)) return(1); if (m->oargs.nfargs != (m->otype==MAT_DIELECTRIC ? 5 : 8)) objerror(m, USER, "bad arguments"); raytexture(r, m->omod); /* get modifiers */ if ( (hastexture = DOT(r->pert,r->pert) > FTINY*FTINY) ) cos1 = raynormal(dnorm, r); /* perturb normal */ else { VCOPY(dnorm, r->ron); cos1 = r->rod; } flatsurface = r->ro != NULL && isflat(r->ro->otype) && !hastexture | (r->crtype & AMBIENT); /* index of refraction */ if (m->otype == MAT_DIELECTRIC) nratio = m->oargs.farg[3] + m->oargs.farg[4]/MLAMBDA; else nratio = m->oargs.farg[3] / m->oargs.farg[7]; if (cos1 < 0.0) { /* inside */ hastexture = -hastexture; cos1 = -cos1; dnorm[0] = -dnorm[0]; dnorm[1] = -dnorm[1]; dnorm[2] = -dnorm[2]; setcolor(r->cext, -mylog(m->oargs.farg[0]*colval(r->pcol,RED)), -mylog(m->oargs.farg[1]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[2]*colval(r->pcol,BLU))); setcolor(r->albedo, 0., 0., 0.); r->gecc = 0.; if (m->otype == MAT_INTERFACE) { setcolor(ctrans, -mylog(m->oargs.farg[4]*colval(r->pcol,RED)), -mylog(m->oargs.farg[5]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[6]*colval(r->pcol,BLU))); setcolor(talb, 0., 0., 0.); } else { copycolor(ctrans, cextinction); copycolor(talb, salbedo); } } else { /* outside */ nratio = 1.0 / nratio; setcolor(ctrans, -mylog(m->oargs.farg[0]*colval(r->pcol,RED)), -mylog(m->oargs.farg[1]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[2]*colval(r->pcol,BLU))); setcolor(talb, 0., 0., 0.); if (m->otype == MAT_INTERFACE) { setcolor(r->cext, -mylog(m->oargs.farg[4]*colval(r->pcol,RED)), -mylog(m->oargs.farg[5]*colval(r->pcol,GRN)), -mylog(m->oargs.farg[6]*colval(r->pcol,BLU))); setcolor(r->albedo, 0., 0., 0.); r->gecc = 0.; } } d2 = 1.0 - nratio*nratio*(1.0 - cos1*cos1); /* compute cos theta2 */ if (d2 < FTINY) /* total reflection */ refl = 1.0; else { /* refraction occurs */ /* compute Fresnel's equations */ cos2 = sqrt(d2); d1 = cos1; d2 = nratio*cos2; d1 = (d1 - d2) / (d1 + d2); refl = d1 * d1; d1 = 1.0 / cos1; d2 = nratio / cos2; d1 = (d1 - d2) / (d1 + d2); refl += d1 * d1; refl *= 0.5; trans = 1.0 - refl; trans *= nratio*nratio; /* solid angle ratio */ setcolor(p.rcoef, trans, trans, trans); if (rayorigin(&p, REFRACTED, r, p.rcoef) == 0) { /* compute refracted ray */ d1 = nratio*cos1 - cos2; for (i = 0; i < 3; i++) p.rdir[i] = nratio*r->rdir[i] + d1*dnorm[i]; /* accidental reflection? */ if (hastexture && DOT(p.rdir,r->ron)*hastexture >= -FTINY) { d1 *= (double)hastexture; for (i = 0; i < 3; i++) /* ignore texture */ p.rdir[i] = nratio*r->rdir[i] + d1*r->ron[i]; normalize(p.rdir); /* not exact */ } else checknorm(p.rdir); #ifdef DISPERSE if (m->otype != MAT_DIELECTRIC || r->rod > 0.0 || r->crtype & SHADOW || !directvis || m->oargs.farg[4] == 0.0 || !disperse(m, r, p.rdir, trans, ctrans, talb)) #endif { copycolor(p.cext, ctrans); copycolor(p.albedo, talb); rayvalue(&p); multcolor(p.rcol, p.rcoef); addcolor(r->rcol, p.rcol); /* virtual distance */ if (flatsurface || (1.-FTINY <= nratio) & (nratio <= 1.+FTINY)) r->rxt = r->rot + raydistance(&p); } } } setcolor(p.rcoef, refl, refl, refl); if (!(r->crtype & SHADOW) && rayorigin(&p, REFLECTED, r, p.rcoef) == 0) { /* compute reflected ray */ VSUM(p.rdir, r->rdir, dnorm, 2.*cos1); /* accidental penetration? */ if (hastexture && DOT(p.rdir,r->ron)*hastexture <= FTINY) VSUM(p.rdir, r->rdir, r->ron, 2.*r->rod); checknorm(p.rdir); rayvalue(&p); /* reflected ray value */ multcolor(p.rcol, p.rcoef); /* color contribution */ copycolor(r->mcol, p.rcol); addcolor(r->rcol, p.rcol); /* virtual distance */ r->rmt = r->rot; if (flatsurface) r->rmt += raydistance(&p); } /* rayvalue() computes absorption */ return(1); }
static int disperse( /* check light sources for dispersion */ OBJREC *m, RAY *r, FVECT vt, double tr, COLOR cet, COLOR abt ) { RAY sray; const RAY *entray; FVECT v1, v2, n1, n2; FVECT dv, v2Xdv; double v2Xdvv2Xdv; int success = 0; SRCINDEX si; FVECT vtmp1, vtmp2; double dtmp1, dtmp2; int l1, l2; COLOR ctmp; int i; /* * This routine computes dispersion to the first order using * the following assumptions: * * 1) The dependency of the index of refraction on wavelength * is approximated by Hartmann's equation with lambda0 * equal to zero. * 2) The entry and exit locations are constant with respect * to dispersion. * * The second assumption permits us to model dispersion without * having to sample refracted directions. We assume that the * geometry inside the material is constant, and concern ourselves * only with the relationship between the entering and exiting ray. * We compute the first derivatives of the entering and exiting * refraction with respect to the index of refraction. This * is then used in a first order Taylor series to determine the * index of refraction necessary to send the exiting ray to each * light source. * If an exiting ray hits a light source within the refraction * boundaries, we sum all the frequencies over the disc of the * light source to determine the resulting color. A smaller light * source will therefore exhibit a sharper spectrum. */ if (!(r->crtype & REFRACTED)) { /* ray started in material */ VCOPY(v1, r->rdir); n1[0] = -r->rdir[0]; n1[1] = -r->rdir[1]; n1[2] = -r->rdir[2]; } else { /* find entry point */ for (entray = r; entray->rtype != REFRACTED; entray = entray->parent) ; entray = entray->parent; if (entray->crtype & REFRACTED) /* too difficult */ return(0); VCOPY(v1, entray->rdir); VCOPY(n1, entray->ron); } VCOPY(v2, vt); /* exiting ray */ VCOPY(n2, r->ron); /* first order dispersion approx. */ dtmp1 = 1./DOT(n1, v1); dtmp2 = 1./DOT(n2, v2); for (i = 0; i < 3; i++) dv[i] = v1[i] + v2[i] - n1[i]*dtmp1 - n2[i]*dtmp2; if (DOT(dv, dv) <= FTINY) /* null effect */ return(0); /* compute plane normal */ fcross(v2Xdv, v2, dv); v2Xdvv2Xdv = DOT(v2Xdv, v2Xdv); /* check sources */ initsrcindex(&si); while (srcray(&sray, r, &si)) { if (DOT(sray.rdir, v2) < MINCOS) continue; /* bad source */ /* adjust source ray */ dtmp1 = DOT(v2Xdv, sray.rdir) / v2Xdvv2Xdv; sray.rdir[0] -= dtmp1 * v2Xdv[0]; sray.rdir[1] -= dtmp1 * v2Xdv[1]; sray.rdir[2] -= dtmp1 * v2Xdv[2]; l1 = lambda(m, v2, dv, sray.rdir); /* mean lambda */ if (l1 > MAXLAMBDA || l1 < MINLAMBDA) /* not visible */ continue; /* trace source ray */ copycolor(sray.cext, cet); copycolor(sray.albedo, abt); normalize(sray.rdir); rayvalue(&sray); if (bright(sray.rcol) <= FTINY) /* missed it */ continue; /* * Compute spectral sum over diameter of source. * First find directions for rays going to opposite * sides of source, then compute wavelengths for each. */ fcross(vtmp1, v2Xdv, sray.rdir); dtmp1 = sqrt(si.dom / v2Xdvv2Xdv / PI); /* compute first ray */ VSUM(vtmp2, sray.rdir, vtmp1, dtmp1); l1 = lambda(m, v2, dv, vtmp2); /* first lambda */ if (l1 < 0) continue; /* compute second ray */ VSUM(vtmp2, sray.rdir, vtmp1, -dtmp1); l2 = lambda(m, v2, dv, vtmp2); /* second lambda */ if (l2 < 0) continue; /* compute color from spectrum */ if (l1 < l2) spec_rgb(ctmp, l1, l2); else spec_rgb(ctmp, l2, l1); multcolor(ctmp, sray.rcol); scalecolor(ctmp, tr); addcolor(r->rcol, ctmp); success++; } return(success); }
/* Load previously accumulated values */ void reload_output() { int i, j; MODCONT *mp; int ofl; char oname[1024]; char *fmode = "rb"; char *outvfmt; LUENT *oent; int xr, yr; STREAMOUT sout; DCOLOR rgbv; if (outfmt == 'a') fmode = "r"; outvfmt = formstr(outfmt); /* reload modifier values */ for (i = 0; i < nmods; i++) { mp = (MODCONT *)lu_find(&modconttab,modname[i])->data; if (mp->outspec == NULL) error(USER, "cannot reload from stdout"); if (mp->outspec[0] == '!') error(USER, "cannot reload from command"); for (j = 0; ; j++) { /* load each modifier bin */ ofl = ofname(oname, mp->outspec, mp->modname, j); if (ofl < 0) error(USER, "bad output file specification"); oent = lu_find(&ofiletab, oname); if (oent->data != NULL) { sout = *(STREAMOUT *)oent->data; } else { sout.reclen = 0; sout.outpipe = 0; sout.xr = xres; sout.yr = yres; sout.ofp = NULL; } if (sout.ofp == NULL) { /* open output as input */ sout.ofp = fopen(oname, fmode); if (sout.ofp == NULL) { if (j == mp->nbins) break; /* assume end of modifier */ sprintf(errmsg, "missing reload file '%s'", oname); error(WARNING, errmsg); break; } #ifdef getc_unlocked flockfile(sout.ofp); #endif if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) { sprintf(errmsg, "format mismatch for '%s'", oname); error(USER, errmsg); } if ((sout.xr > 0) & (sout.yr > 0) && (!fscnresolu(&xr, &yr, sout.ofp) || (xr != sout.xr) | (yr != sout.yr))) { sprintf(errmsg, "resolution mismatch for '%s'", oname); error(USER, errmsg); } } /* read in RGB value */ if (!get_contrib(rgbv, sout.ofp)) { if (!j) { fclose(sout.ofp); break; /* ignore empty file */ } if (j < mp->nbins) { sprintf(errmsg, "missing data in '%s'", oname); error(USER, errmsg); } break; } if (j >= mp->nbins) { /* check modifier size */ sprintf(errmsg, "mismatched -bn setting for reloading '%s'", modname[i]); error(USER, errmsg); } copycolor(mp->cbin[j], rgbv); if (oent->key == NULL) /* new file entry */ oent->key = strcpy((char *) malloc(strlen(oname)+1), oname); if (oent->data == NULL) oent->data = (char *)malloc(sizeof(STREAMOUT)); *(STREAMOUT *)oent->data = sout; } } lu_doall(&ofiletab, &myclose, NULL); /* close all files */ }
static void dirbrdf( /* compute source contribution */ COLOR cval, /* returned coefficient */ void *nnp, /* material data */ FVECT ldir, /* light source direction */ double omega /* light source size */ ) { BRDFDAT *np = nnp; double ldot; double dtmp; COLOR ctmp; FVECT ldx; static double vldx[5], pt[MAXDIM]; char **sa; int i; #define lddx (vldx+1) setcolor(cval, 0.0, 0.0, 0.0); ldot = DOT(np->pnorm, ldir); if (ldot <= FTINY && ldot >= -FTINY) return; /* too close to grazing */ if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY) return; /* wrong side */ if (ldot > 0.0) { /* * Compute and add diffuse reflected component to returned * color. The diffuse reflected component will always be * modified by the color of the material. */ copycolor(ctmp, np->rdiff); dtmp = ldot * omega / PI; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } else { /* * Diffuse transmitted component. */ copycolor(ctmp, np->tdiff); dtmp = -ldot * omega / PI; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } if (ldot > 0.0 ? np->rspec <= FTINY : np->tspec <= FTINY) return; /* diffuse only */ /* set up function */ setbrdfunc(np); sa = np->mp->oargs.sarg; errno = 0; /* transform light vector */ multv3(ldx, ldir, funcxf.xfm); for (i = 0; i < 3; i++) lddx[i] = ldx[i]/funcxf.sca; lddx[3] = omega; /* compute BRTDF */ if (np->mp->otype == MAT_BRTDF) { if (sa[6][0] == '0') /* special case */ colval(ctmp,RED) = 0.0; else colval(ctmp,RED) = funvalue(sa[6], 4, lddx); if (sa[7][0] == '0') colval(ctmp,GRN) = 0.0; else if (!strcmp(sa[7],sa[6])) colval(ctmp,GRN) = colval(ctmp,RED); else colval(ctmp,GRN) = funvalue(sa[7], 4, lddx); if (!strcmp(sa[8],sa[6])) colval(ctmp,BLU) = colval(ctmp,RED); else if (!strcmp(sa[8],sa[7])) colval(ctmp,BLU) = colval(ctmp,GRN); else colval(ctmp,BLU) = funvalue(sa[8], 4, lddx); dtmp = bright(ctmp); } else if (np->dp == NULL) { dtmp = funvalue(sa[0], 4, lddx); setcolor(ctmp, dtmp, dtmp, dtmp); } else { for (i = 0; i < np->dp->nd; i++) pt[i] = funvalue(sa[3+i], 4, lddx); vldx[0] = datavalue(np->dp, pt); dtmp = funvalue(sa[0], 5, vldx); setcolor(ctmp, dtmp, dtmp, dtmp); } if ((errno == EDOM) | (errno == ERANGE)) { objerror(np->mp, WARNING, "compute error"); return; } if (dtmp <= FTINY) return; if (ldot > 0.0) { /* * Compute reflected non-diffuse component. */ if ((np->mp->otype == MAT_MFUNC) | (np->mp->otype == MAT_MDATA)) multcolor(ctmp, np->mcolor); dtmp = ldot * omega * np->rspec; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } else { /* * Compute transmitted non-diffuse component. */ if ((np->mp->otype == MAT_TFUNC) | (np->mp->otype == MAT_TDATA)) multcolor(ctmp, np->mcolor); dtmp = -ldot * omega * np->tspec; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } #undef lddx }
static void pixtoval(void) /* convert picture to values */ { register COLOR *scanln; int dogamma; COLOR lastc; RREAL hv[2]; int startprim, endprim; long startpos; int y; register int x; scanln = (COLOR *)malloc(scanlen(&picres)*sizeof(COLOR)); if (scanln == NULL) { fprintf(stderr, "%s: out of memory\n", progname); quit(1); } dogamma = gamcor < .95 || gamcor > 1.05; if (putprim == ALL && !interleave) { startprim = RED; endprim = BLU; startpos = ftell(fin); } else { startprim = putprim; endprim = putprim; } for (putprim = startprim; putprim <= endprim; putprim++) { if (putprim != startprim && fseek(fin, startpos, 0)) { fprintf(stderr, "%s: seek error on input file\n", progname); quit(1); } set_io(); setcolor(lastc, 0.0, 0.0, 0.0); for (y = 0; y < numscans(&picres); y++) { if (freadscan(scanln, scanlen(&picres), fin) < 0) { fprintf(stderr, "%s: read error\n", progname); quit(1); } for (x = 0; x < scanlen(&picres); x++) { if (uniq) { if ( colval(scanln[x],RED) == colval(lastc,RED) && colval(scanln[x],GRN) == colval(lastc,GRN) && colval(scanln[x],BLU) == colval(lastc,BLU) ) continue; else copycolor(lastc, scanln[x]); } if (doexposure) multcolor(scanln[x], exposure); if (dogamma) setcolor(scanln[x], pow(colval(scanln[x],RED), 1.0/gamcor), pow(colval(scanln[x],GRN), 1.0/gamcor), pow(colval(scanln[x],BLU), 1.0/gamcor)); if (!dataonly) { pix2loc(hv, &picres, x, y); printf("%7d %7d ", (int)(hv[0]*picres.xr), (int)(hv[1]*picres.yr)); } if ((*putval)(scanln[x]) < 0) { fprintf(stderr, "%s: write error\n", progname); quit(1); } } } } free((void *)scanln); }