/* Add normal direction if missing */ static void check_normal_incidence(void) { static FVECT norm_vec = {.0, .0, 1.}; const int saved_nprocs = nprocs; RBFNODE *near_rbf, *mir_rbf, *rbf; double bestd; int n; if (dsf_list == NULL) return; /* XXX should be error? */ near_rbf = dsf_list; bestd = input_orient*near_rbf->invec[2]; if (single_plane_incident) { /* ordered plane incidence? */ if (bestd >= 1.-2.*FTINY) return; /* already have normal */ } else { switch (inp_coverage) { case INP_QUAD1: case INP_QUAD2: case INP_QUAD3: case INP_QUAD4: break; /* quadrilateral symmetry? */ default: return; /* else we can interpolate */ } for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) { const double d = input_orient*rbf->invec[2]; if (d >= 1.-2.*FTINY) return; /* seems we have normal */ if (d > bestd) { near_rbf = rbf; bestd = d; } } } if (mig_list != NULL) { /* need to be called first */ fprintf(stderr, "%s: Late call to check_normal_incidence()\n", progname); exit(1); } #ifdef DEBUG fprintf(stderr, "Interpolating normal incidence by mirroring (%.1f,%.1f)\n", get_theta180(near_rbf->invec), get_phi360(near_rbf->invec)); #endif /* mirror nearest incidence */ n = sizeof(RBFNODE) + sizeof(RBFVAL)*(near_rbf->nrbf-1); mir_rbf = (RBFNODE *)malloc(n); if (mir_rbf == NULL) goto memerr; memcpy(mir_rbf, near_rbf, n); mir_rbf->ord = near_rbf->ord - 1; /* not used, I think */ mir_rbf->next = NULL; mir_rbf->ejl = NULL; rev_rbf_symmetry(mir_rbf, MIRROR_X|MIRROR_Y); nprocs = 1; /* compute migration matrix */ if (create_migration(mir_rbf, near_rbf) == NULL) exit(1); /* XXX should never happen! */ norm_vec[2] = input_orient; /* interpolate normal dist. */ rbf = e_advect_rbf(mig_list, norm_vec, 0); nprocs = saved_nprocs; /* final clean-up */ free(mir_rbf); free(mig_list); mig_list = near_rbf->ejl = NULL; insert_dsf(rbf); /* insert interpolated normal */ return; memerr: fprintf(stderr, "%s: Out of memory in check_normal_incidence()\n", progname); exit(1); }
/* Read a BSDF mesh interpolant from the given binary stream */ int load_bsdf_rep(FILE *ifp) { RBFNODE rbfh; int from_ord, to_ord; int i; clear_bsdf_rep(); if (ifp == NULL) return(0); if (getheader(ifp, headline, NULL) < 0 || single_plane_incident < 0 | !input_orient | !output_orient) { fprintf(stderr, "%s: missing/bad format for BSDF interpolant\n", progname); return(0); } rbfh.next = NULL; /* read each DSF */ rbfh.ejl = NULL; while ((rbfh.ord = getint(4, ifp)) >= 0) { RBFNODE *newrbf; rbfh.invec[0] = getflt(ifp); rbfh.invec[1] = getflt(ifp); rbfh.invec[2] = getflt(ifp); if (normalize(rbfh.invec) == 0) { fprintf(stderr, "%s: zero incident vector\n", progname); return(0); } rbfh.vtotal = getflt(ifp); rbfh.nrbf = getint(4, ifp); newrbf = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(rbfh.nrbf-1)); if (newrbf == NULL) goto memerr; memcpy(newrbf, &rbfh, sizeof(RBFNODE)-sizeof(RBFVAL)); for (i = 0; i < rbfh.nrbf; i++) { newrbf->rbfa[i].peak = getflt(ifp); newrbf->rbfa[i].crad = getint(2, ifp) & 0xffff; newrbf->rbfa[i].gx = getint(1, ifp) & 0xff; newrbf->rbfa[i].gy = getint(1, ifp) & 0xff; } if (feof(ifp)) goto badEOF; /* insert in global list */ if (insert_dsf(newrbf) != rbfh.ord) { fprintf(stderr, "%s: error adding DSF\n", progname); return(0); } } /* read each migration matrix */ while ((from_ord = getint(4, ifp)) >= 0 && (to_ord = getint(4, ifp)) >= 0) { RBFNODE *from_rbf = get_dsf(from_ord); RBFNODE *to_rbf = get_dsf(to_ord); MIGRATION *newmig; int n; if ((from_rbf == NULL) | (to_rbf == NULL)) { fprintf(stderr, "%s: bad DSF reference in migration edge\n", progname); return(0); } n = from_rbf->nrbf * to_rbf->nrbf; newmig = (MIGRATION *)malloc(sizeof(MIGRATION) + sizeof(float)*(n-1)); if (newmig == NULL) goto memerr; newmig->rbfv[0] = from_rbf; newmig->rbfv[1] = to_rbf; memset(newmig->mtx, 0, sizeof(float)*n); for (i = 0; ; ) { /* read sparse data */ int zc = getint(1, ifp) & 0xff; if ((i += zc) >= n) break; if (zc == 0xff) continue; newmig->mtx[i++] = getflt(ifp); } if (feof(ifp)) goto badEOF; /* insert in edge lists */ newmig->enxt[0] = from_rbf->ejl; from_rbf->ejl = newmig; newmig->enxt[1] = to_rbf->ejl; to_rbf->ejl = newmig; /* push onto global list */ newmig->next = mig_list; mig_list = newmig; } return(1); /* success! */ memerr: fprintf(stderr, "%s: Out of memory in load_bsdf_rep()\n", progname); exit(1); badEOF: fprintf(stderr, "%s: Unexpected EOF in load_bsdf_rep()\n", progname); return(0); }
/* Count up filled nodes and build RBF representation from current grid */ RBFNODE * make_rbfrep(void) { int niter = 16; double lastVar, thisVar = 100.; int nn; RBFNODE *newnode; RBFVAL *itera; int i, j; /* compute RBF radii */ compute_radii(); /* coagulate lobes */ cull_values(); nn = 0; /* count selected bins */ for (i = 0; i < GRIDRES; i++) for (j = 0; j < GRIDRES; j++) nn += dsf_grid[i][j].nval; /* compute minimum BSDF */ comp_bsdf_min(); /* allocate RBF array */ newnode = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1)); if (newnode == NULL) goto memerr; newnode->ord = -1; newnode->next = NULL; newnode->ejl = NULL; newnode->invec[2] = sin((M_PI/180.)*theta_in_deg); newnode->invec[0] = cos((M_PI/180.)*phi_in_deg)*newnode->invec[2]; newnode->invec[1] = sin((M_PI/180.)*phi_in_deg)*newnode->invec[2]; newnode->invec[2] = input_orient*sqrt(1. - newnode->invec[2]*newnode->invec[2]); newnode->vtotal = 0; newnode->nrbf = nn; nn = 0; /* fill RBF array */ for (i = 0; i < GRIDRES; i++) for (j = 0; j < GRIDRES; j++) if (dsf_grid[i][j].nval) { newnode->rbfa[nn].peak = dsf_grid[i][j].vsum; newnode->rbfa[nn].crad = RSCA*dsf_grid[i][j].crad + .5; newnode->rbfa[nn].gx = i; newnode->rbfa[nn].gy = j; ++nn; } /* iterate to improve interpolation accuracy */ itera = (RBFVAL *)malloc(sizeof(RBFVAL)*newnode->nrbf); if (itera == NULL) goto memerr; memcpy(itera, newnode->rbfa, sizeof(RBFVAL)*newnode->nrbf); do { double dsum = 0, dsum2 = 0; nn = 0; for (i = 0; i < GRIDRES; i++) for (j = 0; j < GRIDRES; j++) if (dsf_grid[i][j].nval) { FVECT odir; double corr; ovec_from_pos(odir, i, j); itera[nn++].peak *= corr = dsf_grid[i][j].vsum / eval_rbfrep(newnode, odir); dsum += 1. - corr; dsum2 += (1.-corr)*(1.-corr); } memcpy(newnode->rbfa, itera, sizeof(RBFVAL)*newnode->nrbf); lastVar = thisVar; thisVar = dsum2/(double)nn; #ifdef DEBUG fprintf(stderr, "Avg., RMS error: %.1f%% %.1f%%\n", 100.*dsum/(double)nn, 100.*sqrt(thisVar)); #endif } while (--niter > 0 && lastVar-thisVar > 0.02*lastVar); free(itera); nn = 0; /* compute sum for normalization */ while (nn < newnode->nrbf) newnode->vtotal += rbf_volume(&newnode->rbfa[nn++]); #ifdef DEBUG fprintf(stderr, "Integrated DSF at (%.1f,%.1f) deg. is %.2f\n", get_theta180(newnode->invec), get_phi360(newnode->invec), newnode->vtotal); #endif insert_dsf(newnode); return(newnode); memerr: fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname); exit(1); }