/* initiallinking.c */ #include "galerkinP.h" #include "formfactor.h" #include "shaftculling.h" #include "geom.h" #include "scene.h" #include "patch.h" #include "ui.h" #include "error.h" #include "basis.h" static ELEMENT *the_element; /* the element for which initial links are to be created */ static ROLE the_role; /* the role of that element: SOURCE or RECEIVER */ static PATCH *the_patch; /* the patch for the element is the toplevel element */ static BOUNDINGBOX the_patch_bounds; /* bounding box for that patch */ static GEOMLIST *the_candlist; /* candidate list for shaft culling */ void CreateInitialLink(PATCH *patch) { ELEMENT *rcv=(ELEMENT *)NULL, *src=(ELEMENT *)NULL; GEOMLIST *oldcandlist = the_candlist; INTERACTION link; float ff[MAXBASISSIZE*MAXBASISSIZE]; link.K.p = ff; /* link.deltaK.p = */ if (!Facing(patch, the_patch)) return; switch (the_role) { case SOURCE: rcv=TOPLEVEL_ELEMENT(patch); src=the_element; break; case RECEIVER: rcv=the_element; src=TOPLEVEL_ELEMENT(patch); break; default: Fatal(2, "CreateInitialLink", "Impossible element role"); } if ((gal.exact_visibility || gal.shaftcullmode == ALWAYS_DO_SHAFTCULLING) && oldcandlist) { SHAFT shaft, *the_shaft; if (gal.exact_visibility) { POLYGON rcvpoly, srcpoly; the_shaft = ConstructPolygonToPolygonShaft(ElementPolygon(rcv, &rcvpoly), ElementPolygon(src, &srcpoly), &shaft); } else { BOUNDINGBOX bbox; the_shaft = ConstructShaft(the_patch_bounds, PatchBounds(patch, bbox), &shaft); } if (the_shaft) { ShaftOmit(&shaft, (GEOM *)the_patch); ShaftOmit(&shaft, (GEOM *)patch); the_candlist = DoShaftCulling(oldcandlist, the_shaft, (GEOMLIST *)NULL); if (the_shaft->cut == TRUE) { /* one patch causes full occlusion. */ FreeCandidateList(the_candlist); the_candlist = oldcandlist; return; } } else { /* should never happen though */ Warning("CreateInitialLinks", "Unable to construct a shaft for shaft culling"); } } link.rcv = rcv; link.src = src; link.nrcv = rcv->basis_size; link.nsrc = src->basis_size; AreaToAreaFormFactor(&link, the_candlist); if (gal.exact_visibility || gal.shaftcullmode == ALWAYS_DO_SHAFTCULLING) { if (oldcandlist != the_candlist) FreeCandidateList(the_candlist); the_candlist = oldcandlist; } if (link.vis > 0) { /* store interactions with the source patch for the progressive radiosity method * and with the receiving patch for gathering mathods. */ if (gal.iteration_method == SOUTHWELL) src->interactions = InteractionListAdd(src->interactions, InteractionDuplicate(&link)); else rcv->interactions = InteractionListAdd(rcv->interactions, InteractionDuplicate(&link)); } if (gal.wake_up) { ProcessWaitingEvents(); gal.wake_up = FALSE; } } /* yes ... we exploit the hierarchical structure of the scene during initial linking */ static void GeomLink(GEOM *geom) { SHAFT shaft; GEOMLIST *oldCandList = the_candlist; /* immediately return if the GEOM is bounded and behind the plane of the patch * for which itneractions are created ... */ if (geom->bounded && BoundsBehindPlane(GeomBounds(geom), &the_patch->normal, the_patch->plane_constant)) return; /* if the geometry is bounded, do shaft culling, reducing the candidate list * which contains the possible occluders between a pair of patches for which * an initial link will need to be created. */ if (geom->bounded && oldCandList) { ConstructShaft(the_patch_bounds, GeomBounds(geom), &shaft); ShaftOmit(&shaft, (GEOM *)the_patch); the_candlist = DoShaftCulling(oldCandList, &shaft, GeomListCreate()); } /* if the GEOM is an aggregate, test each of it's childer GEOMs, if it * is a primitive, create an initial link with each patch it consists of. */ if (GeomIsAggregate(geom)) { GEOMLIST *geoml = GeomPrimList(geom); GeomListIterate(geoml, GeomLink); } else { PATCHLIST *patchl = GeomPatchList(geom); PatchListIterate(patchl, CreateInitialLink); } if (geom->bounded && oldCandList) FreeCandidateList(the_candlist); the_candlist = oldCandList; } /* Creates the initial interactions for a toplevel element which is * considered to be a SOURCE or RECEIVER according to 'role'. Interactions * are stored at the receiver element when doing gathering and at the * source element when doing shooting. */ void CreateInitialLinks(ELEMENT *top, ROLE role) { if (IsCluster(top)) Fatal(-1, "CreateInitialLinks", "cannot use this routine for cluster elements"); the_element = top; the_role = role; the_patch = top->pog.patch; PatchBounds(the_patch, the_patch_bounds); the_candlist = ClusteredWorld; GeomListIterate(World, GeomLink); } /* Creates an initial link between the given element and the top cluster. */ void CreateInitialLinkWithTopCluster(ELEMENT *elem, ROLE role) { ELEMENT *rcv=(ELEMENT *)NULL, *src=(ELEMENT *)NULL; INTERACTION *link; FloatOrPointer K, deltaK; float ff[MAXBASISSIZE*MAXBASISSIZE]; int i; /* #ident <<< WMP */ #ifdef WMP_WEIGHTS float FK[MAXBASISSIZE]; #endif /* #ident >>> WMP */ switch (role) { case RECEIVER: rcv=elem; src=gal.top_cluster; break; case SOURCE: src=elem; rcv=gal.top_cluster; break; default: Fatal(-1, "CreateInitialLinkWithTopCluster", "Invalid role"); } /* assume no light transport (overlapping receiver and source) */ if (rcv->basis_size * src->basis_size == 1) K.f = 0.; else { K.p = ff; for (i=0; ibasis_size * src->basis_size; i++) K.p[i] = 0.; } deltaK.f = HUGE; /* HUGE error on the form factor */ /* #ident <<< WMP */ #ifdef WMP_WEIGHTS for(i = 0; i < rcv->basis_size; i++) FK[i] = 0.0; #endif /* #ident >>> WMP */ link = InteractionCreate(rcv, src, K, deltaK, rcv->basis_size /*nrcv*/, src->basis_size /*nsrc*/, /*crcv*/ 1, /*vis*/ 128 /* #ident <<< WMP */ #ifdef WMP_WEIGHTS ,FK #endif /* #ident >>> WMP */ ); /* store interactions with the source patch for the progressive radiosity method * and with the receiving patch for gathering mathods. */ if (gal.iteration_method == SOUTHWELL) src->interactions = InteractionListAdd(src->interactions, link); else rcv->interactions = InteractionListAdd(rcv->interactions, link); }