home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
RADIANCE
/
SRC
/
GEN
/
MKILLUM2.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-07
|
9KB
|
365 lines
/* Copyright (c) 1991 Regents of the University of California */
#ifndef lint
static char SCCSid[] = "@(#)mkillum2.c 2.5 8/13/92 LBL";
#endif
/*
* Routines to do the actual calculation for mkillum
*/
#include "mkillum.h"
#include "face.h"
#include "cone.h"
#include "random.h"
o_default(ob, il, rt, nm) /* default illum action */
OBJREC *ob;
struct illum_args *il;
struct rtproc *rt;
char *nm;
{
sprintf(errmsg, "(%s): cannot make illum for %s \"%s\"",
nm, ofun[ob->otype].funame, ob->oname);
error(WARNING, errmsg);
printobj(il->altmat, ob);
}
o_face(ob, il, rt, nm) /* make an illum face */
OBJREC *ob;
struct illum_args *il;
struct rtproc *rt;
char *nm;
{
#define MAXMISS (5*n*il->nsamps)
int dim[3];
int n, nalt, nazi, h;
float *distarr;
double sp[2], r1, r2;
FVECT dn, org, dir;
FVECT u, v;
double ur[2], vr[2];
int nmisses;
register FACE *fa;
register int i, j;
/* get/check arguments */
fa = getface(ob);
if (fa->area == 0.0) {
freeface(ob);
o_default(ob, il, rt, nm);
return;
}
/* set up sampling */
if (il->sampdens <= 0)
nalt = nazi = 1;
else {
n = PI * il->sampdens;
nalt = sqrt(n/PI) + .5;
nazi = PI*nalt + .5;
}
n = nalt*nazi;
distarr = (float *)calloc(n, 3*sizeof(float));
if (distarr == NULL)
error(SYSTEM, "out of memory in o_face");
/* take first edge longer than sqrt(area) */
for (j = fa->nv-1, i = 0; i < fa->nv; j = i++) {
u[0] = VERTEX(fa,i)[0] - VERTEX(fa,j)[0];
u[1] = VERTEX(fa,i)[1] - VERTEX(fa,j)[1];
u[2] = VERTEX(fa,i)[2] - VERTEX(fa,j)[2];
if ((r1 = DOT(u,u)) >= fa->area-FTINY)
break;
}
if (i < fa->nv) { /* got one! -- let's align our axes */
r2 = 1.0/sqrt(r1);
u[0] *= r2; u[1] *= r2; u[2] *= r2;
fcross(v, fa->norm, u);
} else /* oh well, we'll just have to wing it */
mkaxes(u, v, fa->norm);
/* now, find limits in (u,v) coordinates */
ur[0] = vr[0] = FHUGE;
ur[1] = vr[1] = -FHUGE;
for (i = 0; i < fa->nv; i++) {
r1 = DOT(VERTEX(fa,i),u);
if (r1 < ur[0]) ur[0] = r1;
if (r1 > ur[1]) ur[1] = r1;
r2 = DOT(VERTEX(fa,i),v);
if (r2 < vr[0]) vr[0] = r2;
if (r2 > vr[1]) vr[1] = r2;
}
dim[0] = random();
/* sample polygon */
nmisses = 0;
for (dim[1] = 0; dim[1] < nalt; dim[1]++)
for (dim[2] = 0; dim[2] < nazi; dim[2]++)
for (i = 0; i < il->nsamps; i++) {
/* random direction */
h = ilhash(dim, 3) + i;
multisamp(sp, 2, urand(h));
r1 = (dim[1] + sp[0])/nalt;
r2 = (dim[2] + sp[1] - .5)/nazi;
flatdir(dn, r1, r2);
for (j = 0; j < 3; j++)
dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*fa->norm[j];
/* random location */
do {
multisamp(sp, 2, urand(h+4862+nmisses));
r1 = ur[0] + (ur[1]-ur[0]) * sp[0];
r2 = vr[0] + (vr[1]-vr[0]) * sp[1];
for (j = 0; j < 3; j++)
org[j] = r1*u[j] + r2*v[j]
+ fa->offset*fa->norm[j];
} while (!inface(org, fa) && nmisses++ < MAXMISS);
if (nmisses > MAXMISS) {
objerror(ob, WARNING, "bad aspect");
rt->nrays = 0;
freeface(ob);
free((char *)distarr);
o_default(ob, il, rt, nm);
return;
}
for (j = 0; j < 3; j++)
org[j] += .001*fa->norm[j];
/* send sample */
raysamp(distarr+3*(dim[1]*nazi+dim[2]), org, dir, rt);
}
rayflush(rt);
/* write out the face and its distribution */
if (average(il, distarr, nalt*nazi)) {
if (il->sampdens > 0)
flatout(il, distarr, nalt, nazi, u, v, fa->norm);
illumout(il, ob);
} else
printobj(il->altmat, ob);
/* clean up */
freeface(ob);
free((char *)distarr);
#undef MAXMISS
}
o_sphere(ob, il, rt, nm) /* make an illum sphere */
register OBJREC *ob;
struct illum_args *il;
struct rtproc *rt;
char *nm;
{
int dim[3];
int n, nalt, nazi;
float *distarr;
double sp[4], r1, r2, r3;
FVECT org, dir;
FVECT u, v;
register int i, j;
/* check arguments */
if (ob->oargs.nfargs != 4)
objerror(ob, USER, "bad # of arguments");
/* set up sampling */
if (il->sampdens <= 0)
nalt = nazi = 1;
else {
n = 4.*PI * il->sampdens;
nalt = sqrt(n/PI) + .5;
nazi = PI*nalt + .5;
}
n = nalt*nazi;
distarr = (float *)calloc(n, 3*sizeof(float));
if (distarr == NULL)
error(SYSTEM, "out of memory in o_sphere");
dim[0] = random();
/* sample sphere */
for (dim[1] = 0; dim[1] < nalt; dim[1]++)
for (dim[2] = 0; dim[2] < nazi; dim[2]++)
for (i = 0; i < il->nsamps; i++) {
/* next sample point */
multisamp(sp, 4, urand(ilhash(dim,3)+i));
/* random direction */
r1 = (dim[1] + sp[0])/nalt;
r2 = (dim[2] + sp[1] - .5)/nazi;
rounddir(dir, r1, r2);
/* random location */
mkaxes(u, v, dir); /* yuck! */
r3 = sqrt(sp[2]);
r2 = 2.*PI*sp[3];
r1 = r3*ob->oargs.farg[3]*cos(r2);
r2 = r3*ob->oargs.farg[3]*sin(r2);
r3 = ob->oargs.farg[3]*sqrt(1.01-r3*r3);
for (j = 0; j < 3; j++) {
org[j] = ob->oargs.farg[j] + r1*u[j] + r2*v[j] +
r3*dir[j];
dir[j] = -dir[j];
}
/* send sample */
raysamp(distarr+3*(dim[1]*nazi+dim[2]), org, dir, rt);
}
rayflush(rt);
/* write out the sphere and its distribution */
if (average(il, distarr, nalt*nazi)) {
if (il->sampdens > 0)
roundout(il, distarr, nalt, nazi);
else
objerror(ob, WARNING, "diffuse distribution");
illumout(il, ob);
} else
printobj(il->altmat, ob);
/* clean up */
free((char *)distarr);
}
o_ring(ob, il, rt, nm) /* make an illum ring */
OBJREC *ob;
struct illum_args *il;
struct rtproc *rt;
char *nm;
{
int dim[3];
int n, nalt, nazi;
float *distarr;
double sp[4], r1, r2, r3;
FVECT dn, org, dir;
FVECT u, v;
register CONE *co;
register int i, j;
/* get/check arguments */
co = getcone(ob, 0);
/* set up sampling */
if (il->sampdens <= 0)
nalt = nazi = 1;
else {
n = PI * il->sampdens;
nalt = sqrt(n/PI) + .5;
nazi = PI*nalt + .5;
}
n = nalt*nazi;
distarr = (float *)calloc(n, 3*sizeof(float));
if (distarr == NULL)
error(SYSTEM, "out of memory in o_ring");
mkaxes(u, v, co->ad);
dim[0] = random();
/* sample disk */
for (dim[1] = 0; dim[1] < nalt; dim[1]++)
for (dim[2] = 0; dim[2] < nazi; dim[2]++)
for (i = 0; i < il->nsamps; i++) {
/* next sample point */
multisamp(sp, 4, urand(ilhash(dim,3)+i));
/* random direction */
r1 = (dim[1] + sp[0])/nalt;
r2 = (dim[2] + sp[1] - .5)/nazi;
flatdir(dn, r1, r2);
for (j = 0; j < 3; j++)
dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*co->ad[j];
/* random location */
r3 = sqrt(CO_R0(co)*CO_R0(co) +
sp[2]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co)));
r2 = 2.*PI*sp[3];
r1 = r3*cos(r2);
r2 = r3*sin(r2);
for (j = 0; j < 3; j++)
org[j] = CO_P0(co)[j] + r1*u[j] + r1*v[j] +
.001*co->ad[j];
/* send sample */
raysamp(distarr+3*(dim[1]*nazi+dim[2]), org, dir, rt);
}
rayflush(rt);
/* write out the ring and its distribution */
if (average(il, distarr, nalt*nazi)) {
if (il->sampdens > 0)
flatout(il, distarr, nalt, nazi, u, v, co->ad);
illumout(il, ob);
} else
printobj(il->altmat, ob);
/* clean up */
freecone(ob);
free((char *)distarr);
}
raysamp(res, org, dir, rt) /* compute a ray sample */
float res[3];
FVECT org, dir;
register struct rtproc *rt;
{
register float *fp;
if (rt->nrays == rt->bsiz)
rayflush(rt);
rt->dest[rt->nrays] = res;
fp = rt->buf + 6*rt->nrays++;
*fp++ = org[0]; *fp++ = org[1]; *fp++ = org[2];
*fp++ = dir[0]; *fp++ = dir[1]; *fp = dir[2];
}
rayflush(rt) /* flush buffered rays */
register struct rtproc *rt;
{
register int i;
if (rt->nrays <= 0)
return;
bzero(rt->buf+6*rt->nrays, 6*sizeof(float));
errno = 0;
if ( process(rt->pd, (char *)rt->buf, (char *)rt->buf,
3*sizeof(float)*rt->nrays,
6*sizeof(float)*(rt->nrays+1)) <
3*sizeof(float)*rt->nrays )
error(SYSTEM, "error reading from rtrace process");
i = rt->nrays;
while (i--) {
rt->dest[i][0] += rt->buf[3*i];
rt->dest[i][1] += rt->buf[3*i+1];
rt->dest[i][2] += rt->buf[3*i+2];
}
rt->nrays = 0;
}
mkaxes(u, v, n) /* compute u and v to go with n */
FVECT u, v, n;
{
register int i;
v[0] = v[1] = v[2] = 0.0;
for (i = 0; i < 3; i++)
if (n[i] < 0.6 && n[i] > -0.6)
break;
v[i] = 1.0;
fcross(u, v, n);
normalize(u);
fcross(v, n, u);
}
rounddir(dv, alt, azi) /* compute uniform spherical direction */
register FVECT dv;
double alt, azi;
{
double d1, d2;
dv[2] = 1. - 2.*alt;
d1 = sqrt(1. - dv[2]*dv[2]);
d2 = 2.*PI * azi;
dv[0] = d1*cos(d2);
dv[1] = d1*sin(d2);
}
flatdir(dv, alt, azi) /* compute uniform hemispherical direction */
register FVECT dv;
double alt, azi;
{
double d1, d2;
d1 = sqrt(alt);
d2 = 2.*PI * azi;
dv[0] = d1*cos(d2);
dv[1] = d1*sin(d2);
dv[2] = sqrt(1. - alt);
}