| 8 |
|
*/ |
| 9 |
|
|
| 10 |
|
#include <stdlib.h> |
| 11 |
+ |
#include "platform.h" |
| 12 |
|
#include "rtio.h" |
| 13 |
|
#include "rtmath.h" |
| 14 |
|
#include "random.h" |
| 63 |
|
int ntotal; /* surfaces+subsurfaces */ |
| 64 |
|
IDF_OBJECT *pfirst; /* first matching object */ |
| 65 |
|
IDF_OBJECT *plast; /* last before subsurfaces */ |
| 66 |
+ |
float *area_redu; /* subsurface area per surf. */ |
| 67 |
|
} ZONE; /* a list of collected zone surfaces */ |
| 68 |
|
|
| 69 |
|
ZONE *zone_list = NULL; /* our list of zones */ |
| 100 |
|
znew->next = zone_list; |
| 101 |
|
znew->pfirst = znew->plast = param; |
| 102 |
|
znew->ntotal = znew->nsurf = 1; |
| 103 |
+ |
znew->area_redu = NULL; |
| 104 |
|
return(zone_list = znew); |
| 105 |
|
} |
| 106 |
|
|
| 177 |
|
static IDF_FIELD * |
| 178 |
|
get_vlist(IDF_OBJECT *param, const char *zname) |
| 179 |
|
{ |
| 180 |
< |
int i = 0; |
| 180 |
> |
#define itm_len (sizeof(IDF_FIELD)+6) |
| 181 |
> |
static char fld_buf[4*itm_len]; |
| 182 |
> |
static char *next_fbp = fld_buf; |
| 183 |
> |
int i; |
| 184 |
> |
IDF_FIELD *res; |
| 185 |
|
/* check if subsurface */ |
| 186 |
|
if (!strcmp(param->pname, SUBSURF_PNAME)) { |
| 187 |
|
if (zname != NULL) { |
| 190 |
|
if (strcmp((*(ZONE *)lep->data).zname, zname)) |
| 191 |
|
return(NULL); |
| 192 |
|
} |
| 193 |
< |
return(idf_getfield(param, SS_VERT_FLD)); |
| 193 |
> |
res = idf_getfield(param, SS_VERT_FLD); |
| 194 |
> |
} else { |
| 195 |
> |
i = 0; /* check for surface type */ |
| 196 |
> |
while (strcmp(surf_type[i].pname, param->pname)) |
| 197 |
> |
if (surf_type[++i].pname == NULL) |
| 198 |
> |
return(NULL); |
| 199 |
> |
|
| 200 |
> |
if (zname != NULL) { /* matches specified zone? */ |
| 201 |
> |
IDF_FIELD *fptr = idf_getfield(param, surf_type[i].zone_fld); |
| 202 |
> |
if (fptr == NULL || strcmp(fptr->val, zname)) |
| 203 |
> |
return(NULL); |
| 204 |
> |
} |
| 205 |
> |
res = idf_getfield(param, surf_type[i].vert_fld); |
| 206 |
|
} |
| 207 |
< |
/* check for surface type */ |
| 208 |
< |
while (strcmp(surf_type[i].pname, param->pname)) |
| 209 |
< |
if (surf_type[++i].pname == NULL) |
| 207 |
> |
if (!res->val[0]) { /* hack for missing #vert */ |
| 208 |
> |
IDF_FIELD *fptr; |
| 209 |
> |
if (next_fbp >= fld_buf+sizeof(fld_buf)) |
| 210 |
> |
next_fbp = fld_buf; |
| 211 |
> |
i = 0; /* count vertices */ |
| 212 |
> |
for (fptr = res->next; fptr != NULL; fptr = fptr->next) |
| 213 |
> |
++i; |
| 214 |
> |
if (i % 3) |
| 215 |
|
return(NULL); |
| 216 |
< |
|
| 217 |
< |
if (zname != NULL) { /* matches specified zone? */ |
| 218 |
< |
IDF_FIELD *fptr = idf_getfield(param, surf_type[i].zone_fld); |
| 219 |
< |
if (fptr == NULL || strcmp(fptr->val, zname)) |
| 220 |
< |
return(NULL); |
| 216 |
> |
fptr = res->next; |
| 217 |
> |
res = (IDF_FIELD *)next_fbp; next_fbp += itm_len; |
| 218 |
> |
res->next = fptr; |
| 219 |
> |
res->rem = ""; |
| 220 |
> |
sprintf(res->val, "%d", i/3); |
| 221 |
|
} |
| 222 |
< |
/* return field for #verts */ |
| 223 |
< |
return(idf_getfield(param, surf_type[i].vert_fld)); |
| 222 |
> |
return(res); |
| 223 |
> |
#undef itm_len |
| 224 |
|
} |
| 225 |
|
|
| 226 |
|
/* Get/allocate surface polygon */ |
| 321 |
|
} |
| 322 |
|
|
| 323 |
|
/* Convert subsurface to Radiance with modifier based on unique name */ |
| 324 |
< |
static int |
| 324 |
> |
static double |
| 325 |
|
rad_subsurface(IDF_OBJECT *param, FILE *ofp) |
| 326 |
|
{ |
| 327 |
|
const char *sname = idf_getfield(param,NAME_FLD)->val; |
| 328 |
< |
SURFACE *surf = get_surface(idf_getfield(param,SS_VERT_FLD)); |
| 328 |
> |
SURFACE *surf = get_surface(get_vlist(param, NULL)); |
| 329 |
> |
double area; |
| 330 |
|
int i; |
| 331 |
|
|
| 332 |
|
if (surf == NULL) { |
| 333 |
|
fprintf(stderr, "%s: bad subsurface '%s'\n", progname, sname); |
| 334 |
< |
return(0); |
| 334 |
> |
return(-1.); |
| 335 |
|
} |
| 336 |
|
fprintf(ofp, "\nvoid glow '%s'\n0\n0\n4 1 1 1 0\n", sname); |
| 337 |
|
fprintf(ofp, "\n'%s' polygon 'ss_%s'\n0\n0\n%d\n", |
| 341 |
|
VSUM(vert, surf->vl[i], surf->norm, 2.*SURF_EPS); |
| 342 |
|
fprintf(ofp, "\t%.12f %.12f %.12f\n", vert[0], vert[1], vert[2]); |
| 343 |
|
} |
| 344 |
+ |
area = surf->area; |
| 345 |
|
free(surf); |
| 346 |
< |
return(!ferror(ofp)); |
| 346 |
> |
if (ferror(ofp)) |
| 347 |
> |
return(-1.); |
| 348 |
> |
return(area); |
| 349 |
|
} |
| 350 |
|
|
| 351 |
|
/* Start rcontrib process */ |
| 361 |
|
FILE *ofp; |
| 362 |
|
IDF_OBJECT *pptr; |
| 363 |
|
IDF_FIELD *fptr; |
| 364 |
< |
int i, n; |
| 364 |
> |
int i, j, n; |
| 365 |
|
/* start oconv command */ |
| 366 |
< |
sprintf(cbuf, "oconv - > '%s'", temp_octree); |
| 366 |
> |
sprintf(cbuf, "oconv - > \"%s\"", temp_octree); |
| 367 |
|
if ((ofp = popen(cbuf, "w")) == NULL) { |
| 368 |
|
fputs(progname, stderr); |
| 369 |
|
fputs(": cannot open oconv process\n", stderr); |
| 391 |
|
av[i++] = fptr->val; |
| 392 |
|
} |
| 393 |
|
/* now subsurfaces */ |
| 394 |
+ |
if (zp->ntotal > zp->nsurf) { |
| 395 |
+ |
if (zp->area_redu != NULL) |
| 396 |
+ |
memset(zp->area_redu, 0, sizeof(float)*zp->ntotal); |
| 397 |
+ |
else if ((zp->area_redu = (float *)calloc(zp->ntotal, |
| 398 |
+ |
sizeof(float))) == NULL) |
| 399 |
+ |
return(0); |
| 400 |
+ |
} |
| 401 |
|
for ( ; n < zp->ntotal; n++, pptr = pptr->dnext) { |
| 402 |
+ |
double ssarea; |
| 403 |
+ |
const char *bname; |
| 404 |
+ |
IDF_OBJECT *pptr1; |
| 405 |
|
fptr = idf_getfield(pptr,NAME_FLD); |
| 406 |
|
if (fptr == NULL || !fptr->val[0]) { |
| 407 |
|
fputs(progname, stderr); |
| 408 |
|
fputs(": missing name for subsurface object\n", stderr); |
| 409 |
|
return(0); |
| 410 |
|
} |
| 411 |
< |
if (!rad_subsurface(pptr, ofp)) /* add surface to octree */ |
| 411 |
> |
/* add subsurface to octree */ |
| 412 |
> |
if ((ssarea = rad_subsurface(pptr, ofp)) < 0) |
| 413 |
|
return(0); |
| 414 |
+ |
/* mark area for subtraction */ |
| 415 |
+ |
bname = idf_getfield(pptr,SS_BASE_FLD)->val; |
| 416 |
+ |
for (j = 0, pptr1 = zp->pfirst; |
| 417 |
+ |
j < zp->nsurf; j++, pptr1 = pptr1->dnext) |
| 418 |
+ |
if (!strcmp(idf_getfield(pptr1,NAME_FLD)->val, bname)) { |
| 419 |
+ |
zp->area_redu[j] += ssarea; |
| 420 |
+ |
break; |
| 421 |
+ |
} |
| 422 |
|
av[i++] = "-m"; |
| 423 |
|
av[i++] = fptr->val; |
| 424 |
|
} |
| 539 |
|
} |
| 540 |
|
|
| 541 |
|
/* Sample the given surface */ |
| 542 |
< |
static int |
| 542 |
> |
static double |
| 543 |
|
sample_surface(IDF_OBJECT *param, int wd) |
| 544 |
|
{ |
| 545 |
|
POLYSAMP psamp; |
| 546 |
+ |
double area; |
| 547 |
|
int nv; |
| 548 |
|
Vert2_list *vlist2; |
| 549 |
|
/* set up our polygon sampler */ |
| 551 |
|
fprintf(stderr, "%s: bad polygon %s '%s'\n", |
| 552 |
|
progname, param->pname, |
| 553 |
|
idf_getfield(param,NAME_FLD)->val); |
| 554 |
< |
return(0); |
| 554 |
> |
return(-1.); |
| 555 |
|
} |
| 556 |
|
psamp.samp_left = nsamps; /* assign samples & destination */ |
| 557 |
|
psamp.wd = wd; |
| 558 |
|
/* hack for subsurface sampling */ |
| 559 |
|
psamp.poff += 2.*SURF_EPS * !strcmp(param->pname, SUBSURF_PNAME); |
| 560 |
+ |
|
| 561 |
+ |
area = psamp.area_left; /* remember starting surface area */ |
| 562 |
|
/* sample each subtriangle */ |
| 563 |
|
if (!polyTriangulate(vlist2, &sample_triangle)) |
| 564 |
< |
return(0); |
| 564 |
> |
return(-1.); |
| 565 |
|
polyFree(vlist2); /* clean up and return */ |
| 566 |
< |
return(1); |
| 566 |
> |
return(area); |
| 567 |
|
} |
| 568 |
|
|
| 569 |
|
/* Compute User View Factors using open rcontrib process */ |
| 595 |
|
/* UVFs from each surface */ |
| 596 |
|
for (n = 0, pptr = zp->pfirst; n < zp->ntotal; n++, pptr = pptr->dnext) { |
| 597 |
|
double vfsum = 0; |
| 598 |
+ |
double adj_factor; |
| 599 |
|
/* send samples to rcontrib */ |
| 600 |
< |
if (!sample_surface(pptr, pd->w)) |
| 600 |
> |
if ((adj_factor = sample_surface(pptr, pd->w)) < 0) |
| 601 |
|
return(0); |
| 602 |
+ |
if (zp->area_redu == NULL) |
| 603 |
+ |
adj_factor = 1.; |
| 604 |
+ |
else /* comp. for subsurface area */ |
| 605 |
+ |
adj_factor /= adj_factor - zp->area_redu[n]; |
| 606 |
|
/* read results */ |
| 607 |
|
if (readbuf(pd->r, (char *)uvfa, sizeof(float)*3*zp->ntotal) != |
| 608 |
|
sizeof(float)*3*zp->ntotal) { |
| 613 |
|
/* append UVF fields */ |
| 614 |
|
for (m = 0, pptr1 = zp->pfirst; |
| 615 |
|
m < zp->ntotal; m++, pptr1 = pptr1->dnext) { |
| 616 |
< |
vfsum += uvfa[3*m + 1]; |
| 617 |
< |
if (pptr1 == pptr && uvfa[3*m + 1] > .001) |
| 616 |
> |
const double uvf = uvfa[3*m + 1] * adj_factor; |
| 617 |
> |
vfsum += uvf; |
| 618 |
> |
if (pptr1 == pptr && uvf > .001) |
| 619 |
|
fprintf(stderr, |
| 620 |
|
"%s: warning - non-zero self-VF (%.1f%%) for surface '%s'\n", |
| 621 |
< |
progname, 100.*uvfa[3*m + 1], |
| 621 |
> |
progname, 100.*uvf, |
| 622 |
|
idf_getfield(pptr,NAME_FLD)->val); |
| 623 |
< |
sprintf(uvfbuf, "%.4f", uvfa[3*m + 1]); |
| 623 |
> |
sprintf(uvfbuf, "%.4f", uvf); |
| 624 |
|
if (!idf_addfield(pout, |
| 625 |
|
idf_getfield(pptr,NAME_FLD)->val, NULL) || |
| 626 |
|
!idf_addfield(pout, |
| 717 |
|
do { |
| 718 |
|
pnext = pptr->pnext; |
| 719 |
|
idf_delobject(our_idf, pptr); |
| 720 |
< |
} while (pnext != NULL); |
| 720 |
> |
} while ((pptr = pnext) != NULL); |
| 721 |
|
} |
| 722 |
|
/* add to header */ |
| 723 |
|
if (our_idf->hrem == NULL || |