ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdfrep.c
(Generate patch)

Comparing ray/src/cv/bsdfrep.c (file contents):
Revision 2.1 by greg, Fri Oct 19 04:14:29 2012 UTC vs.
Revision 2.37 by greg, Wed Dec 15 01:38:50 2021 UTC

# Line 13 | Line 13 | static const char RCSid[] = "$Id$";
13   #include "rtio.h"
14   #include "resolu.h"
15   #include "bsdfrep.h"
16 <                                /* which quadrants are represented */
16 > #include "random.h"
17 >                                /* name and manufacturer if known */
18 > char                    bsdf_name[256];
19 > char                    bsdf_manuf[256];
20 >                                /* active grid resolution */
21 > int                     grid_res = GRIDRES;
22 >
23 >                                /* coverage/symmetry using INP_QUAD? flags */
24   int                     inp_coverage = 0;
25                                  /* all incident angles in-plane so far? */
26   int                     single_plane_incident = -1;
# Line 22 | Line 29 | int                    single_plane_incident = -1;
29   int                     input_orient = 0;
30   int                     output_orient = 0;
31  
32 +                                /* represented color space */
33 + RBColor                 rbf_colorimetry = RBCunknown;
34 +
35 + const char              *RBCident[] = {
36 +                                "CIE-Y", "CIE-XYZ", "Spectral", "Unknown"
37 +                        };
38 +
39 +                                /* BSDF histogram */
40 + unsigned long           bsdf_hist[HISTLEN];
41 +
42 +                                /* BSDF value for boundary regions */
43 + double                  bsdf_min = 0;
44 + double                  bsdf_spec_val = 0;
45 + double                  bsdf_spec_rad = 0;
46 +
47                                  /* processed incident DSF measurements */
48   RBFNODE                 *dsf_list = NULL;
49  
# Line 31 | Line 53 | MIGRATION              *mig_list = NULL;
53                                  /* current input direction */
54   double                  theta_in_deg, phi_in_deg;
55  
56 +                                /* header line sharing callback */
57 + int                     (*sir_headshare)(char *s) = NULL;
58 +
59   /* Register new input direction */
60   int
61   new_input_direction(double new_theta, double new_phi)
62   {
38        if (!input_orient)              /* check input orientation */
39                input_orient = 1 - 2*(new_theta > 90.);
40        else if (input_orient > 0 ^ new_theta < 90.) {
41                fprintf(stderr,
42                "%s: Cannot handle input angles on both sides of surface\n",
43                                progname);
44                return(0);
45        }
63                                          /* normalize angle ranges */
64          while (new_theta < -180.)
65                  new_theta += 360.;
# Line 56 | Line 73 | new_input_direction(double new_theta, double new_phi)
73                  new_phi += 360.;
74          while (new_phi >= 360.)
75                  new_phi -= 360.;
76 +                                        /* check input orientation */
77 +        if (!input_orient)
78 +                input_orient = 1 - 2*(new_theta > 90.);
79 +        else if (input_orient > 0 ^ new_theta < 90.) {
80 +                fprintf(stderr,
81 +                "%s: Cannot handle input angles on both sides of surface\n",
82 +                                progname);
83 +                return(0);
84 +        }
85 +        if ((theta_in_deg = new_theta) < 1.0)
86 +                return(1);              /* don't rely on phi near normal */
87          if (single_plane_incident > 0)  /* check input coverage */
88                  single_plane_incident = (round(new_phi) == round(phi_in_deg));
89          else if (single_plane_incident < 0)
90                  single_plane_incident = 1;
63        theta_in_deg = new_theta;       /* assume it's OK */
91          phi_in_deg = new_phi;
92          if ((1. < new_phi) & (new_phi < 89.))
93                  inp_coverage |= INP_QUAD1;
# Line 78 | Line 105 | int
105   use_symmetry(FVECT vec)
106   {
107          double  phi = get_phi360(vec);
108 +                                /* because of -0. issue */
109 +        while (phi >= 360.) phi -= 360.;
110 +        while (phi < 0.) phi += 360.;
111  
112          switch (inp_coverage) {
113          case INP_QUAD1|INP_QUAD2|INP_QUAD3|INP_QUAD4:
# Line 167 | Line 197 | rev_rbf_symmetry(RBFNODE *rbf, int sym)
197          rev_symmetry(rbf->invec, sym);
198          if (sym & MIRROR_X)
199                  for (n = rbf->nrbf; n-- > 0; )
200 <                        rbf->rbfa[n].gx = GRIDRES-1 - rbf->rbfa[n].gx;
200 >                        rbf->rbfa[n].gx = grid_res-1 - rbf->rbfa[n].gx;
201          if (sym & MIRROR_Y)
202                  for (n = rbf->nrbf; n-- > 0; )
203 <                        rbf->rbfa[n].gy = GRIDRES-1 - rbf->rbfa[n].gy;
203 >                        rbf->rbfa[n].gy = grid_res-1 - rbf->rbfa[n].gy;
204   }
205  
206 < /* Compute volume associated with Gaussian lobe */
207 < double
208 < rbf_volume(const RBFVAL *rbfp)
206 > /* Rotate RBF to correspond to given incident vector */
207 > void
208 > rotate_rbf(RBFNODE *rbf, const FVECT invec)
209   {
210 <        double  rad = R2ANG(rbfp->crad);
210 >        static const FVECT      vnorm = {.0, .0, 1.};
211 >        const double            phi = atan2(invec[1],invec[0]) -
212 >                                        atan2(rbf->invec[1],rbf->invec[0]);
213 >        FVECT                   outvec;
214 >        int                     pos[2];
215 >        int                     n;
216  
217 <        return((2.*M_PI) * rbfp->peak * rad*rad);
217 >        for (n = (cos(phi) < 1.-FTINY)*rbf->nrbf; n-- > 0; ) {
218 >                ovec_from_pos(outvec, rbf->rbfa[n].gx, rbf->rbfa[n].gy);
219 >                spinvector(outvec, outvec, vnorm, phi);
220 >                pos_from_vec(pos, outvec);
221 >                rbf->rbfa[n].gx = pos[0];
222 >                rbf->rbfa[n].gy = pos[1];
223 >        }
224 >        VCOPY(rbf->invec, invec);
225   }
226  
227   /* Compute outgoing vector from grid position */
228   void
229   ovec_from_pos(FVECT vec, int xpos, int ypos)
230   {
231 <        double  uv[2];
231 >        RREAL   uv[2];
232          double  r2;
233          
234 <        SDsquare2disk(uv, (1./GRIDRES)*(xpos+.5), (1./GRIDRES)*(ypos+.5));
234 >        square2disk(uv, (xpos+.5)/grid_res, (ypos+.5)/grid_res);
235                                  /* uniform hemispherical projection */
236          r2 = uv[0]*uv[0] + uv[1]*uv[1];
237          vec[0] = vec[1] = sqrt(2. - r2);
# Line 202 | Line 244 | ovec_from_pos(FVECT vec, int xpos, int ypos)
244   void
245   pos_from_vec(int pos[2], const FVECT vec)
246   {
247 <        double  sq[2];          /* uniform hemispherical projection */
247 >        RREAL   sq[2];          /* uniform hemispherical projection */
248          double  norm = 1./sqrt(1. + fabs(vec[2]));
249  
250 <        SDdisk2square(sq, vec[0]*norm, vec[1]*norm);
250 >        disk2square(sq, vec[0]*norm, vec[1]*norm);
251  
252 <        pos[0] = (int)(sq[0]*GRIDRES);
253 <        pos[1] = (int)(sq[1]*GRIDRES);
252 >        pos[0] = (int)(sq[0]*grid_res);
253 >        pos[1] = (int)(sq[1]*grid_res);
254   }
255  
256 < /* Evaluate RBF for DSF at the given normalized outgoing direction */
256 > /* Compute volume associated with Gaussian lobe */
257   double
258 < eval_rbfrep(const RBFNODE *rp, const FVECT outvec)
258 > rbf_volume(const RBFVAL *rbfp)
259   {
260 <        double          res = .0;
260 >        double  rad = R2ANG(rbfp->crad);
261 >        FVECT   odir;
262 >        double  elev, integ;
263 >                                /* infinite integral approximation */
264 >        integ = (2.*M_PI) * rbfp->peak * rad*rad;
265 >                                /* check if we're near horizon */
266 >        ovec_from_pos(odir, rbfp->gx, rbfp->gy);
267 >        elev = output_orient*odir[2];
268 >                                /* apply cut-off correction if > 1% */
269 >        if (elev < 2.8*rad) {
270 >                /* elev = asin(elev);   /* this is so crude, anyway... */
271 >                integ *= 1. - .5*exp(-.5*elev*elev/(rad*rad));
272 >        }
273 >        return(integ);
274 > }
275 >
276 > /* Evaluate BSDF at the given normalized outgoing direction in color */
277 > SDError
278 > eval_rbfcol(SDValue *sv, const RBFNODE *rp, const FVECT outvec)
279 > {
280 >        const double    rfact2 = (38./M_PI/M_PI)*(grid_res*grid_res);
281 >        int             pos[2];
282 >        double          res = 0;
283 >        double          usum = 0, vsum = 0;
284          const RBFVAL    *rbfp;
285          FVECT           odir;
286 <        double          sig2;
286 >        double          rad2;
287          int             n;
288 <
289 <        if (rp == NULL)
290 <                return(.0);
288 >                                /* assign default value */
289 >        sv->spec = c_dfcolor;
290 >        sv->cieY = bsdf_min;
291 >                                /* check for wrong side */
292 >        if (outvec[2] > 0 ^ output_orient > 0) {
293 >                strcpy(SDerrorDetail, "Wrong-side scattering query");
294 >                return(SDEargument);
295 >        }
296 >        if (rp == NULL)         /* return minimum if no information avail. */
297 >                return(SDEnone);
298 >                                /* optimization for fast lobe culling */
299 >        pos_from_vec(pos, outvec);
300 >                                /* sum radial basis function */
301          rbfp = rp->rbfa;
302          for (n = rp->nrbf; n--; rbfp++) {
303 +                int     d2 = (pos[0]-rbfp->gx)*(pos[0]-rbfp->gx) +
304 +                                (pos[1]-rbfp->gy)*(pos[1]-rbfp->gy);
305 +                double  val;
306 +                rad2 = R2ANG(rbfp->crad);
307 +                rad2 *= rad2;
308 +                if (d2 > rad2*rfact2)
309 +                        continue;
310                  ovec_from_pos(odir, rbfp->gx, rbfp->gy);
311 <                sig2 = R2ANG(rbfp->crad);
312 <                sig2 = (DOT(odir,outvec) - 1.) / (sig2*sig2);
313 <                if (sig2 > -19.)
314 <                        res += rbfp->peak * exp(sig2);
311 >                val = rbfp->peak * exp((DOT(odir,outvec) - 1.) / rad2);
312 >                if (rbf_colorimetry == RBCtristimulus) {
313 >                        usum += val * (rbfp->chroma & 0xff);
314 >                        vsum += val * (rbfp->chroma>>8 & 0xff);
315 >                }
316 >                res += val;
317          }
318 <        return(res);
318 >        sv->cieY = res / COSF(outvec[2]);
319 >        if (sv->cieY < bsdf_min) {      /* never return less than bsdf_min */
320 >                sv->cieY = bsdf_min;
321 >        } else if (rbf_colorimetry == RBCtristimulus) {
322 >                C_CHROMA        cres = (int)(usum/res + frandom());
323 >                cres |= (int)(vsum/res + frandom()) << 8;
324 >                c_decodeChroma(&sv->spec, cres);
325 >        }
326 >        return(SDEnone);
327   }
328  
329 + /* Evaluate BSDF at the given normalized outgoing direction in Y */
330 + double
331 + eval_rbfrep(const RBFNODE *rp, const FVECT outvec)
332 + {
333 +        SDValue sv;
334 +
335 +        if (eval_rbfcol(&sv, rp, outvec) == SDEnone)
336 +                return(sv.cieY);
337 +
338 +        return(0.0);
339 + }
340 +
341   /* Insert a new directional scattering function in our global list */
342   int
343   insert_dsf(RBFNODE *newrbf)
# Line 244 | Line 348 | insert_dsf(RBFNODE *newrbf)
348          for (rbf = dsf_list; rbf != NULL; rbf = rbf->next)
349                  if (DOT(rbf->invec, newrbf->invec) >= 1.-FTINY) {
350                          fprintf(stderr,
351 <                                "%s: Duplicate incident measurement (ignored)\n",
352 <                                        progname);
351 >                "%s: Duplicate incident measurement ignored at (%.1f,%.1f)\n",
352 >                                        progname, get_theta180(newrbf->invec),
353 >                                        get_phi360(newrbf->invec));
354                          free(newrbf);
355                          return(-1);
356                  }
# Line 280 | Line 385 | get_dsf(int ord)
385          RBFNODE         *rbf;
386  
387          for (rbf = dsf_list; rbf != NULL; rbf = rbf->next)
388 <                if (rbf->ord == ord);
388 >                if (rbf->ord == ord)
389                          return(rbf);
390          return(NULL);
391   }
# Line 311 | Line 416 | is_rev_tri(const FVECT v1, const FVECT v2, const FVECT
416   int
417   get_triangles(RBFNODE *rbfv[2], const MIGRATION *mig)
418   {
419 <        const MIGRATION *ej, *ej2;
419 >        const MIGRATION *ej1, *ej2;
420          RBFNODE         *tv;
421  
422          rbfv[0] = rbfv[1] = NULL;
423          if (mig == NULL)
424                  return(0);
425 <        for (ej = mig->rbfv[0]->ejl; ej != NULL;
426 <                                ej = nextedge(mig->rbfv[0],ej)) {
427 <                if (ej == mig)
425 >        for (ej1 = mig->rbfv[0]->ejl; ej1 != NULL;
426 >                                ej1 = nextedge(mig->rbfv[0],ej1)) {
427 >                if (ej1 == mig)
428                          continue;
429 <                tv = opp_rbf(mig->rbfv[0],ej);
429 >                tv = opp_rbf(mig->rbfv[0],ej1);
430                  for (ej2 = tv->ejl; ej2 != NULL; ej2 = nextedge(tv,ej2))
431                          if (opp_rbf(tv,ej2) == mig->rbfv[1]) {
432                                  rbfv[is_rev_tri(mig->rbfv[0]->invec,
# Line 333 | Line 438 | get_triangles(RBFNODE *rbfv[2], const MIGRATION *mig)
438          return((rbfv[0] != NULL) + (rbfv[1] != NULL));
439   }
440  
441 + /* Return single-lobe specular RBF for the given incident direction */
442 + RBFNODE *
443 + def_rbf_spec(const FVECT invec)
444 + {
445 +        RBFNODE         *rbf;
446 +        FVECT           ovec;
447 +        int             pos[2];
448 +
449 +        if (input_orient > 0 ^ invec[2] > 0)    /* wrong side? */
450 +                return(NULL);
451 +        if ((bsdf_spec_val <= bsdf_min) | (bsdf_spec_rad <= 0))
452 +                return(NULL);                   /* nothing set */
453 +        rbf = (RBFNODE *)malloc(sizeof(RBFNODE));
454 +        if (rbf == NULL)
455 +                return(NULL);
456 +        ovec[0] = -invec[0];
457 +        ovec[1] = -invec[1];
458 +        ovec[2] = invec[2]*(2*(input_orient==output_orient) - 1);
459 +        pos_from_vec(pos, ovec);
460 +        rbf->ord = 0;
461 +        rbf->next = NULL;
462 +        rbf->ejl = NULL;
463 +        VCOPY(rbf->invec, invec);
464 +        rbf->nrbf = 1;
465 +        rbf->rbfa[0].peak = bsdf_spec_val * COSF(ovec[2]);
466 +        rbf->rbfa[0].chroma = c_dfchroma;
467 +        rbf->rbfa[0].crad = ANG2R(bsdf_spec_rad);
468 +        rbf->rbfa[0].gx = pos[0];
469 +        rbf->rbfa[0].gy = pos[1];
470 +        rbf->vtotal = rbf_volume(rbf->rbfa);
471 +        return(rbf);
472 + }
473 +
474 + /* Advect and allocate new RBF along edge (internal call) */
475 + RBFNODE *
476 + e_advect_rbf(const MIGRATION *mig, const FVECT invec, int lobe_lim)
477 + {
478 +        double          cthresh = FTINY;
479 +        RBFNODE         *rbf;
480 +        int             n, i, j;
481 +        double          t, full_dist;
482 +                                                /* get relative position */
483 +        t = Acos(DOT(invec, mig->rbfv[0]->invec));
484 +        if (t <= .001) {                        /* near first DSF */
485 +                n = sizeof(RBFNODE) + sizeof(RBFVAL)*(mig->rbfv[0]->nrbf-1);
486 +                rbf = (RBFNODE *)malloc(n);
487 +                if (rbf == NULL)
488 +                        goto memerr;
489 +                memcpy(rbf, mig->rbfv[0], n);   /* just duplicate */
490 +                rbf->next = NULL; rbf->ejl = NULL;
491 +                return(rbf);
492 +        }
493 +        full_dist = acos(DOT(mig->rbfv[0]->invec, mig->rbfv[1]->invec));
494 +        if (t >= full_dist-.001) {              /* near second DSF */
495 +                n = sizeof(RBFNODE) + sizeof(RBFVAL)*(mig->rbfv[1]->nrbf-1);
496 +                rbf = (RBFNODE *)malloc(n);
497 +                if (rbf == NULL)
498 +                        goto memerr;
499 +                memcpy(rbf, mig->rbfv[1], n);   /* just duplicate */
500 +                rbf->next = NULL; rbf->ejl = NULL;
501 +                return(rbf);
502 +        }
503 +        t /= full_dist;
504 + tryagain:
505 +        n = 0;                                  /* count migrating particles */
506 +        for (i = 0; i < mtx_nrows(mig); i++)
507 +            for (j = 0; j < mtx_ncols(mig); j++)
508 +                n += (mtx_coef(mig,i,j) > cthresh);
509 +                                                /* are we over our limit? */
510 +        if ((lobe_lim > 0) & (n > lobe_lim)) {
511 +                cthresh = cthresh*2. + 10.*FTINY;
512 +                goto tryagain;
513 +        }
514 + #ifdef DEBUG
515 +        fprintf(stderr, "Input RBFs have %d, %d nodes -> output has %d\n",
516 +                        mig->rbfv[0]->nrbf, mig->rbfv[1]->nrbf, n);
517 + #endif
518 +        rbf = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(n-1));
519 +        if (rbf == NULL)
520 +                goto memerr;
521 +        rbf->next = NULL; rbf->ejl = NULL;
522 +        VCOPY(rbf->invec, invec);
523 +        rbf->nrbf = n;
524 +        rbf->vtotal = 1.-t + t*mig->rbfv[1]->vtotal/mig->rbfv[0]->vtotal;
525 +        n = 0;                                  /* advect RBF lobes */
526 +        for (i = 0; i < mtx_nrows(mig); i++) {
527 +            const RBFVAL        *rbf0i = &mig->rbfv[0]->rbfa[i];
528 +            const float         peak0 = rbf0i->peak;
529 +            const double        rad0 = R2ANG(rbf0i->crad);
530 +            C_COLOR             cc0;
531 +            FVECT               v0;
532 +            float               mv;
533 +            ovec_from_pos(v0, rbf0i->gx, rbf0i->gy);
534 +            c_decodeChroma(&cc0, rbf0i->chroma);
535 +            for (j = 0; j < mtx_ncols(mig); j++)
536 +                if ((mv = mtx_coef(mig,i,j)) > cthresh) {
537 +                        const RBFVAL    *rbf1j = &mig->rbfv[1]->rbfa[j];
538 +                        double          rad2;
539 +                        FVECT           v;
540 +                        int             pos[2];
541 +                        rad2 = R2ANG(rbf1j->crad);
542 +                        rad2 = rad0*rad0*(1.-t) + rad2*rad2*t;
543 +                        rbf->rbfa[n].peak = peak0 * mv * rbf->vtotal *
544 +                                                rad0*rad0/rad2;
545 +                        if (rbf_colorimetry == RBCtristimulus) {
546 +                                C_COLOR cres;
547 +                                c_decodeChroma(&cres, rbf1j->chroma);
548 +                                c_cmix(&cres, 1.-t, &cc0, t, &cres);
549 +                                rbf->rbfa[n].chroma = c_encodeChroma(&cres);
550 +                        } else
551 +                                rbf->rbfa[n].chroma = c_dfchroma;
552 +                        rbf->rbfa[n].crad = ANG2R(sqrt(rad2));
553 +                        ovec_from_pos(v, rbf1j->gx, rbf1j->gy);
554 +                        geodesic(v, v0, v, t, GEOD_REL);
555 +                        pos_from_vec(pos, v);
556 +                        rbf->rbfa[n].gx = pos[0];
557 +                        rbf->rbfa[n].gy = pos[1];
558 +                        ++n;
559 +                }
560 +        }
561 +        rbf->vtotal *= mig->rbfv[0]->vtotal;    /* turn ratio into actual */
562 +        return(rbf);
563 + memerr:
564 +        fprintf(stderr, "%s: Out of memory in e_advect_rbf()\n", progname);
565 +        exit(1);
566 +        return(NULL);   /* pro forma return */
567 + }
568 +
569 + /* Clear our BSDF representation and free memory */
570 + void
571 + clear_bsdf_rep(void)
572 + {
573 +        while (mig_list != NULL) {
574 +                MIGRATION       *mig = mig_list;
575 +                mig_list = mig->next;
576 +                free(mig);
577 +        }
578 +        while (dsf_list != NULL) {
579 +                RBFNODE         *rbf = dsf_list;
580 +                dsf_list = rbf->next;
581 +                free(rbf);
582 +        }
583 +        bsdf_name[0] = '\0';
584 +        bsdf_manuf[0] = '\0';
585 +        inp_coverage = 0;
586 +        single_plane_incident = -1;
587 +        input_orient = output_orient = 0;
588 +        rbf_colorimetry = RBCunknown;
589 +        grid_res = GRIDRES;
590 +        memset(bsdf_hist, 0, sizeof(bsdf_hist));
591 +        bsdf_min = 0;
592 +        bsdf_spec_val = 0;
593 +        bsdf_spec_rad = 0;
594 + }
595 +
596   /* Write our BSDF mesh interpolant out to the given binary stream */
597   void
598   save_bsdf_rep(FILE *ofp)
# Line 341 | Line 601 | save_bsdf_rep(FILE *ofp)
601          MIGRATION       *mig;
602          int             i, n;
603                                          /* finish header */
604 +        if (bsdf_name[0])
605 +                fprintf(ofp, "NAME=%s\n", bsdf_name);
606 +        if (bsdf_manuf[0])
607 +                fprintf(ofp, "MANUFACT=%s\n", bsdf_manuf);
608 +        fprintf(ofp, "SYMMETRY=%d\n", !single_plane_incident * inp_coverage);
609 +        fprintf(ofp, "IO_SIDES= %d %d\n", input_orient, output_orient);
610 +        fprintf(ofp, "COLORIMETRY=%s\n", RBCident[rbf_colorimetry]);
611 +        fprintf(ofp, "GRIDRES=%d\n", grid_res);
612 +        fprintf(ofp, "BSDFMIN=%g\n", bsdf_min);
613 +        if ((bsdf_spec_val > bsdf_min) & (bsdf_spec_rad > 0))
614 +                fprintf(ofp, "BSDFSPEC= %f %f\n", bsdf_spec_val, bsdf_spec_rad);
615          fputformat(BSDFREP_FMT, ofp);
616          fputc('\n', ofp);
617 +        putint(BSDFREP_MAGIC, 2, ofp);
618                                          /* write each DSF */
619          for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) {
620                  putint(rbf->ord, 4, ofp);
# Line 353 | Line 625 | save_bsdf_rep(FILE *ofp)
625                  putint(rbf->nrbf, 4, ofp);
626                  for (i = 0; i < rbf->nrbf; i++) {
627                          putflt(rbf->rbfa[i].peak, ofp);
628 +                        putint(rbf->rbfa[i].chroma, 2, ofp);
629                          putint(rbf->rbfa[i].crad, 2, ofp);
630 <                        putint(rbf->rbfa[i].gx, 1, ofp);
631 <                        putint(rbf->rbfa[i].gy, 1, ofp);
630 >                        putint(rbf->rbfa[i].gx, 2, ofp);
631 >                        putint(rbf->rbfa[i].gy, 2, ofp);
632                  }
633          }
634          putint(-1, 4, ofp);             /* terminator */
635                                          /* write each migration matrix */
636 <        for (mig = mig_list; mig != NULL; mig = mig_list->next) {
636 >        for (mig = mig_list; mig != NULL; mig = mig->next) {
637 >                int     zerocnt = 0;
638                  putint(mig->rbfv[0]->ord, 4, ofp);
639                  putint(mig->rbfv[1]->ord, 4, ofp);
640 +                                        /* write out as sparse data */
641                  n = mtx_nrows(mig) * mtx_ncols(mig);
642 <                for (i = 0; i < n; i++)
643 <                        putflt(mig->mtx[i], ofp);
642 >                for (i = 0; i < n; i++) {
643 >                        if (zerocnt == 0xff) {
644 >                                putint(0xff, 1, ofp); zerocnt = 0;
645 >                        }
646 >                        if (mig->mtx[i] != 0) {
647 >                                putint(zerocnt, 1, ofp); zerocnt = 0;
648 >                                putflt(mig->mtx[i], ofp);
649 >                        } else
650 >                                ++zerocnt;
651 >                }
652 >                putint(zerocnt, 1, ofp);
653          }
654          putint(-1, 4, ofp);             /* terminator */
655          putint(-1, 4, ofp);
# Line 376 | Line 660 | save_bsdf_rep(FILE *ofp)
660          }
661   }
662  
663 + /* Check header line for critical information */
664 + static int
665 + headline(char *s, void *p)
666 + {
667 +        char    fmt[MAXFMTLEN];
668 +        int     i;
669 +
670 +        if (isheadid(s))
671 +                return(0);
672 +        if (!strncmp(s, "NAME=", 5)) {
673 +                strcpy(bsdf_name, s+5);
674 +                bsdf_name[strlen(bsdf_name)-1] = '\0';
675 +                return(1);
676 +        }
677 +        if (!strncmp(s, "MANUFACT=", 9)) {
678 +                strcpy(bsdf_manuf, s+9);
679 +                bsdf_manuf[strlen(bsdf_manuf)-1] = '\0';
680 +                return(1);
681 +        }
682 +        if (!strncmp(s, "SYMMETRY=", 9)) {
683 +                inp_coverage = atoi(s+9);
684 +                single_plane_incident = !inp_coverage;
685 +                return(1);
686 +        }
687 +        if (!strncmp(s, "IO_SIDES=", 9)) {
688 +                sscanf(s+9, "%d %d", &input_orient, &output_orient);
689 +                return(1);
690 +        }
691 +        if (!strncmp(s, "COLORIMETRY=", 12)) {
692 +                fmt[0] = '\0';
693 +                sscanf(s+12, "%s", fmt);
694 +                for (i = RBCunknown; i >= 0; i--)
695 +                        if (!strcmp(fmt, RBCident[i]))
696 +                                break;
697 +                if (i < 0)
698 +                        return(-1);
699 +                rbf_colorimetry = i;
700 +                return(1);
701 +        }
702 +        if (!strncmp(s, "GRIDRES=", 8)) {
703 +                sscanf(s+8, "%d", &grid_res);
704 +                return(1);
705 +        }
706 +        if (!strncmp(s, "BSDFMIN=", 8)) {
707 +                sscanf(s+8, "%lf", &bsdf_min);
708 +                return(1);
709 +        }
710 +        if (!strncmp(s, "BSDFSPEC=", 9)) {
711 +                sscanf(s+9, "%lf %lf", &bsdf_spec_val, &bsdf_spec_rad);
712 +                return(1);
713 +        }
714 +        if (formatval(fmt, s))
715 +                return (strcmp(fmt, BSDFREP_FMT) ? -1 : 0);
716 +        if (sir_headshare != NULL)
717 +                return ((*sir_headshare)(s));
718 +        return(0);
719 + }
720 +
721   /* Read a BSDF mesh interpolant from the given binary stream */
722   int
723   load_bsdf_rep(FILE *ifp)
# Line 383 | Line 725 | load_bsdf_rep(FILE *ifp)
725          RBFNODE         rbfh;
726          int             from_ord, to_ord;
727          int             i;
728 < #ifdef DEBUG
729 <        if ((dsf_list != NULL) | (mig_list != NULL)) {
730 <                fprintf(stderr,
731 <                "%s: attempt to load BSDF interpolant over existing\n",
728 >
729 >        clear_bsdf_rep();
730 >        if (ifp == NULL)
731 >                return(0);
732 >        if (getheader(ifp, headline, NULL) < 0 || (single_plane_incident < 0) |
733 >                        !input_orient | !output_orient |
734 >                        (grid_res < 16) | (grid_res > 0xffff)) {
735 >                fprintf(stderr, "%s: missing/bad format for BSDF interpolant\n",
736                                  progname);
737                  return(0);
738          }
739 < #endif
740 <        if (checkheader(ifp, BSDFREP_FMT, NULL) <= 0) {
395 <                fprintf(stderr, "%s: missing/bad format for BSDF interpolant\n",
739 >        if (getint(2, ifp) != BSDFREP_MAGIC) {
740 >                fprintf(stderr, "%s: bad magic number for BSDF interpolant\n",
741                                  progname);
742                  return(0);
743          }
744 <        rbfh.next = NULL;               /* read each DSF */
400 <        rbfh.ejl = NULL;
744 >        memset(&rbfh, 0, sizeof(rbfh)); /* read each DSF */
745          while ((rbfh.ord = getint(4, ifp)) >= 0) {
746                  RBFNODE         *newrbf;
747  
748                  rbfh.invec[0] = getflt(ifp);
749                  rbfh.invec[1] = getflt(ifp);
750                  rbfh.invec[2] = getflt(ifp);
751 <                rbfh.nrbf = getint(4, ifp);
752 <                if (!new_input_vector(rbfh.invec))
751 >                if (normalize(rbfh.invec) == 0) {
752 >                        fprintf(stderr, "%s: zero incident vector\n", progname);
753                          return(0);
754 +                }
755 +                rbfh.vtotal = getflt(ifp);
756 +                rbfh.nrbf = getint(4, ifp);
757                  newrbf = (RBFNODE *)malloc(sizeof(RBFNODE) +
758                                          sizeof(RBFVAL)*(rbfh.nrbf-1));
759                  if (newrbf == NULL)
760                          goto memerr;
761 <                memcpy(newrbf, &rbfh, sizeof(RBFNODE));
761 >                *newrbf = rbfh;
762                  for (i = 0; i < rbfh.nrbf; i++) {
763                          newrbf->rbfa[i].peak = getflt(ifp);
764 +                        newrbf->rbfa[i].chroma = getint(2, ifp) & 0xffff;
765                          newrbf->rbfa[i].crad = getint(2, ifp) & 0xffff;
766 <                        newrbf->rbfa[i].gx = getint(1, ifp) & 0xff;
767 <                        newrbf->rbfa[i].gy = getint(1, ifp) & 0xff;
766 >                        newrbf->rbfa[i].gx = getint(2, ifp) & 0xffff;
767 >                        newrbf->rbfa[i].gy = getint(2, ifp) & 0xffff;
768                  }
769                  if (feof(ifp))
770                          goto badEOF;
# Line 447 | Line 795 | load_bsdf_rep(FILE *ifp)
795                          goto memerr;
796                  newmig->rbfv[0] = from_rbf;
797                  newmig->rbfv[1] = to_rbf;
798 <                                        /* read matrix coefficients */
799 <                for (i = 0; i < n; i++)
800 <                        newmig->mtx[i] = getflt(ifp);
798 >                memset(newmig->mtx, 0, sizeof(float)*n);
799 >                for (i = 0; ; ) {       /* read sparse data */
800 >                        int     zc = getint(1, ifp) & 0xff;
801 >                        if ((i += zc) >= n)
802 >                                break;
803 >                        if (zc == 0xff)
804 >                                continue;
805 >                        newmig->mtx[i++] = getflt(ifp);
806 >                }
807                  if (feof(ifp))
808                          goto badEOF;
809                                          /* insert in edge lists */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines