--- ray/src/util/glaresrc.c 1991/03/20 13:32:56 1.8 +++ ray/src/util/glaresrc.c 2004/01/02 12:51:54 2.5 @@ -1,14 +1,12 @@ -/* Copyright (c) 1991 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: glaresrc.c,v 2.5 2004/01/02 12:51:54 schorsch Exp $"; #endif - /* * Gather samples and compute glare sources. */ #include "glare.h" +#include "linregr.h" #define vcont(vd,vu) ((vu)-(vd)<=SEPS) #define hcont(s1,s2) ((s1)->r-(s2)->l>=-SEPS&&(s2)->r-(s1)->l>=-SEPS) @@ -16,11 +14,28 @@ static char SCCSid[] = "$SunId$ LBL"; struct source *curlist = NULL; /* current source list */ struct source *donelist = NULL; /* finished sources */ +static struct srcspan * newspan(int l, int r, int v, float *sb); +static struct srcspan * newspan(int l, int r, int v, float *sb); +static void addindirect(int h, int v, double br); +static void addsrcspan(struct srcspan *nss); +static void mergesource(struct source *sp, struct source *ap); +static void close_sources(int v); +static void close_allsrcs(void); +static struct srcspan * splitspan(register struct srcspan *sso, double h, double v, double m); +static struct source * splitsource(struct source *so); +static void donesource(register struct source *sp); +static struct source * findbuddy(register struct source *s, register struct source *l); +static void absorb(register struct source *s); +static void freespans(struct source *sp); -struct srcspan * -newspan(l, r, v, sb) /* allocate a new source span */ -int l, r, v; -float *sb; + +static struct srcspan * +newspan( /* allocate a new source span */ + int l, + int r, + int v, + float *sb +) { register struct srcspan *ss; register int i; @@ -38,7 +53,8 @@ float *sb; } -analyze() /* analyze our scene */ +extern void +analyze(void) /* analyze our scene */ { int h, v; int left; @@ -50,9 +66,11 @@ analyze() /* analyze our scene */ for (v = vsize; v >= -vsize; v--) { close_sources(v); #ifndef DEBUG - if (verbose) + if (verbose) { fprintf(stderr, "%s: analyzing... %3ld%%\r", progname, 100L*(vsize-v)/(2*vsize)); + fflush(stderr); + } #endif getviewspan(v, spanbr); left = hsize + 1; @@ -72,65 +90,70 @@ analyze() /* analyze our scene */ addsrcspan(newspan(left,h,v,spanbr)); left = hsize + 1; } - addindirect(h, spanbr[h+hsize]); + addindirect(h, v, spanbr[h+hsize]); } } if (left < h) addsrcspan(newspan(left,h,v,spanbr)); } - free((char *)spanbr); + free((void *)spanbr); close_allsrcs(); - absorb_specks(); } -addindirect(h, br) /* add brightness to indirect illuminances */ -int h; -double br; +static void +addindirect( /* add brightness to indirect illuminances */ + int h, + int v, + double br +) { double tanb, d; + int hl; register int i; - if (h <= -hlim) { /* left region */ - d = (double)(h+hlim)/sampdens; - if (d <= -1.0+FTINY) + hl = hlim(v); + if (h <= -hl) { /* left region */ + d = (double)(-h-hl)/sampdens; + if (d >= 1.0-FTINY) return; tanb = d/sqrt(1.0-d*d); for (i = 0; i < nglardirs; i++) { d = indirect[i].lcos - tanb*indirect[i].lsin; if (d > 0.0) { indirect[i].sum += d * br; - indirect[i].n++; + indirect[i].n += d; } } return; } - if (h >= hlim) { /* right region */ - d = (double)(h-hlim)/sampdens; - if (d >= 1.0-FTINY) + if (h >= hl) { /* right region */ + d = (double)(-h+hl)/sampdens; + if (d <= -1.0+FTINY) return; tanb = d/sqrt(1.0-d*d); for (i = 0; i < nglardirs; i++) { d = indirect[i].rcos - tanb*indirect[i].rsin; if (d > 0.0) { indirect[i].sum += d * br; - indirect[i].n++; + indirect[i].n += d; } } return; } /* central region */ for (i = 0; i < nglardirs; i++) { - d = cos(h_theta(h) - indirect[i].theta); + d = cos(h_theta(h,v) - indirect[i].theta); if (d > 0.0) { indirect[i].sum += d * br; - indirect[i].n++; + indirect[i].n += d; } } } -comp_thresh() /* compute glare threshold */ +extern void +comp_thresh(void) /* compute glare threshold */ { int h, v; int nsamps; @@ -141,13 +164,14 @@ comp_thresh() /* compute glare threshold */ progname); brsum = 0.0; nsamps = 0; - for (v = vsize; v >= -vsize; v -= TSAMPSTEP) + for (v = vsize; v >= -vsize; v -= TSAMPSTEP) { for (h = -hsize; h <= hsize; h += TSAMPSTEP) { if ((br = getviewpix(h, v)) < 0.0) continue; brsum += br; nsamps++; } + } if (nsamps == 0) { fprintf(stderr, "%s: no viewable scene!\n", progname); exit(1); @@ -168,8 +192,10 @@ comp_thresh() /* compute glare threshold */ } -addsrcspan(nss) /* add new source span to our list */ -struct srcspan *nss; +static void +addsrcspan( /* add new source span to our list */ + struct srcspan *nss +) { struct source *last, *cs, *this; register struct srcspan *ss; @@ -206,8 +232,11 @@ struct srcspan *nss; } -mergesource(sp, ap) /* merge source ap into source sp */ -struct source *sp, *ap; +static void +mergesource( /* merge source ap into source sp */ + struct source *sp, + struct source *ap +) { struct srcspan head; register struct srcspan *alp, *prev, *tp; @@ -236,12 +265,14 @@ struct source *sp, *ap; sp->brt = (sp->brt*sp->dom + ap->brt*ap->dom) / (sp->dom + ap->dom); } - free((char *)ap); + free((void *)ap); } -close_sources(v) /* close sources above v */ -int v; +static void +close_sources( /* close sources above v */ + int v +) { struct source head; register struct source *last, *this; @@ -259,7 +290,8 @@ int v; } -close_allsrcs() /* done with everything */ +static void +close_allsrcs(void) /* done with everything */ { register struct source *this, *next; @@ -273,48 +305,138 @@ close_allsrcs() /* done with everything */ } -donesource(sp) /* finished with this source */ -register struct source *sp; +static struct srcspan * +splitspan( /* divide source span at point */ + register struct srcspan *sso, + double h, + double v, + double m +) { - FVECT dthis, dright; + register struct srcspan *ssn; + double d; + int hs; + + d = h - m*(sso->v - v); + hs = d < 0. ? d-.5 : d+.5; + if (sso->l >= hs) + return(NULL); + if (sso->r <= hs) + return(sso); + /* need to split it */ + ssn = (struct srcspan *)malloc(sizeof(struct srcspan)); + if (ssn == NULL) + memerr("source spans in splitspan"); + ssn->brsum = (double)(hs - sso->l)/(sso->r - sso->l) * sso->brsum; + sso->brsum -= ssn->brsum; + ssn->v = sso->v; + ssn->l = sso->l; + ssn->r = sso->l = hs; + return(ssn); +} + + +static struct source * +splitsource( /* divide source in two if it's big and long */ + struct source *so +) +{ + LRSUM lr; + LRLIN fit; + register struct srcspan *ss, *ssn; + struct srcspan *ssl, *ssnl, head; + int h; + double mh, mv; + struct source *sn; + + lrclear(&lr); + for (ss = so->first; ss != NULL; ss = ss->next) + for (h = ss->l; h < ss->r; h++) + lrpoint(h, ss->v, &lr); + if ((double)lr.n/(sampdens*sampdens) < SABIG) + return(NULL); /* too small */ + if (lrfit(&fit, &lr) < 0) + return(NULL); /* can't fit a line */ + if (fit.correlation < LCORR && fit.correlation > -LCORR) + return(NULL); + if (verbose) + fprintf(stderr, "%s: splitting large source\n", progname); + mh = lrxavg(&lr); + mv = lryavg(&lr); + sn = (struct source *)malloc(sizeof(struct source)); + if (sn == NULL) + memerr("source records in splitsource"); + sn->dom = 0.0; + sn->first = NULL; + ssnl = NULL; + head.next = so->first; + ssl = &head; + for (ss = so->first; ss != NULL; ssl = ss, ss = ss->next) + if ((ssn = splitspan(ss, mh, mv, fit.slope)) != NULL) { + if (ssn == ss) { /* remove from old */ + ssl->next = ss->next; + ss = ssl; + } + if (ssnl == NULL) /* add to new */ + sn->first = ssn; + else + ssnl->next = ssn; + ssn->next = NULL; + ssnl = ssn; + } + so->first = head.next; + return(sn); +} + + +static void +donesource( /* finished with this source */ + register struct source *sp +) +{ + struct source *newsrc; register struct srcspan *ss; int h, n; - double d; + double hsum, vsum, d; + while ((newsrc = splitsource(sp)) != NULL) /* split it? */ + donesource(newsrc); sp->dom = 0.0; - sp->dir[0] = sp->dir[1] = sp->dir[2] = 0.0; + hsum = vsum = 0.0; sp->brt = 0.0; n = 0; for (ss = sp->first; ss != NULL; ss = ss->next) { sp->brt += ss->brsum; n += ss->r - ss->l; - if (compdir(dright, ss->r, ss->v) < 0) - compdir(dright, ss->r-2, ss->v); - for (h = ss->r-1; h >= ss->l; h--) - if (compdir(dthis, h, ss->v) == 0) { - d = dist2(dthis, dright); - fvsum(sp->dir, sp->dir, dthis, d); - sp->dom += d; - VCOPY(dright, dthis); - } - free((char *)ss); + for (h = ss->l; h < ss->r; h++) { + d = pixsize(h, ss->v); + hsum += d*h; + vsum += d*ss->v; + sp->dom += d; + } } - sp->first = NULL; + freespans(sp); + if (sp->dom <= FTINY) { /* must be right at edge of image */ + free((void *)sp); + return; + } sp->brt /= (double)n; - normalize(sp->dir); + compdir(sp->dir, (int)(hsum/sp->dom), (int)(vsum/sp->dom)); sp->next = donelist; donelist = sp; if (verbose) fprintf(stderr, - "%s: found source at (%.3f,%.3f,%.3f), dw %.5f, br %.1f (%d samps)\n", + "%s: source at [%.3f,%.3f,%.3f], dw %.5f, br %.1f (%d samps)\n", progname, sp->dir[0], sp->dir[1], sp->dir[2], sp->dom, sp->brt, n); } -struct source * -findbuddy(s, l) /* find close enough source to s in l*/ -register struct source *s, *l; +static struct source * +findbuddy( /* find close enough source to s in l*/ + register struct source *s, + register struct source *l +) { struct source *bestbuddy = NULL; double d, r, mindist = MAXBUDDY; @@ -331,7 +453,8 @@ register struct source *s, *l; } -absorb_specks() /* eliminate too-small sources */ +extern void +absorb_specks(void) /* eliminate too-small sources */ { struct source head, *buddy; register struct source *last, *this; @@ -340,10 +463,10 @@ absorb_specks() /* eliminate too-small sources */ fprintf(stderr, "%s: absorbing small sources...\n", progname); head.next = donelist; last = &head; - for (this = donelist; this != NULL; this = this->next) + for (this = head.next; this != NULL; this = this->next) if (TOOSMALL(this)) { last->next = this->next; - buddy = findbuddy(this, donelist); + buddy = findbuddy(this, head.next); if (buddy != NULL) mergesource(buddy, this); else @@ -355,21 +478,37 @@ absorb_specks() /* eliminate too-small sources */ } -absorb(s) /* absorb a source into indirect */ -register struct source *s; +static void +absorb( /* absorb a source into indirect */ + register struct source *s +) { FVECT dir; - register int i, n; + double d; + register int i; for (i = 0; i < nglardirs; i++) { spinvector(dir, ourview.vdir, ourview.vup, indirect[i].theta); - n = DOT(dir,s->dir)*s->dom*(sampdens*sampdens) + 0.5; - if (n == 0) + d = DOT(dir,s->dir)*s->dom*(sampdens*sampdens); + if (d <= 0.0) continue; - indirect[i].sum += n * s->brt; - indirect[i].n += n; + indirect[i].sum += d * s->brt; + indirect[i].n += d; } - for ( ; s->first != NULL; s->first = s->first->next) - free((char *)s->first); - free((char *)s); + freespans(s); + free((void *)s); +} + + +static void +freespans( /* free spans associated with source */ + struct source *sp +) +{ + register struct srcspan *ss; + + while ((ss = sp->first) != NULL) { + sp->first = ss->next; + free((void *)ss); + } }