blob: e77b42cac69ecf4783473890201111adfb58d8b2 [file] [log] [blame]
/*************************************************************************/
/* */
/* Copyright (c) 1994 Stanford University */
/* */
/* All rights reserved. */
/* */
/* Permission is given to use, copy, and modify this software for any */
/* non-commercial purpose as long as this copyright notice is not */
/* removed. All other uses, including redistribution in whole or in */
/* part, are forbidden without prior written permission. */
/* */
/* This software is provided with absolutely no warranty and no */
/* support. */
/* */
/*************************************************************************/
/**************************************************************
*
* Visibility testing
*
*
***************************************************************/
#include <stdio.h>
#include <math.h>
EXTERN_ENV;
include(radiosity.h)
#define VIS_RANGE_MARGIN (0.01)
#define VISI_RAYS_MAX (16)
#define VISI_POOL_NO (16)
#define FABS(x) (((x) < 0)?-(x):(x))
float rand_ray1[VISI_RAYS_MAX][2], rand_ray2[VISI_RAYS_MAX][2] ;
struct v_struct {
char pad1[PAGE_SIZE]; /* padding to avoid false-sharing
and allow page-placement */
Patch *v_src_patch, *v_dest_patch ;
Vertex v_src_p1, v_dest_p1 ;
Vertex v_src_v12, v_src_v13 ;
Vertex v_dest_v12, v_dest_v13 ;
long bsp_nodes_visited, total_bsp_nodes_visited ;
Ray ray_pool[VISI_POOL_NO];
Vertex point_pool[VISI_POOL_NO];
long pool_dst_hits; /* Number of rays that hit the destination */
Patch *patch_cache[PATCH_CACHE_SIZE] ;
char pad2[PAGE_SIZE]; /* padding to avoid false-sharing
and allow page-placement */
} vis_struct[MAX_PROCESSORS];
/*************************************************************
*
* void init_visibility_module()
*
* initialize the random test rays array.
*
* Test ray parameters are precomputed as follows.
* (1) The triangles are divided into 16 small triangles.
* (2) Each small triangle shoots a ray to a small triangle on the
* destination. If N-rays are requested by get_test_ray(),
* N small triangles are chosen on the source and the destination
* and a ray is shot between N pairs of the small triangles.
* (3) Current scheme selects pairs of the small triangles in a static
* manner. The pairs are chosen such that rays are equally
* distributed.
*
*************************************************************/
void init_visibility_module(long process_id)
{
#define TTICK (1.0/12.0)
/* Three corner triangles. P(i) -- Q(i) */
rand_ray1[0][0] = TTICK ; rand_ray1[0][1] = TTICK ;
rand_ray1[1][0] = TTICK ; rand_ray1[1][1] = TTICK * 10 ;
rand_ray1[2][0] = TTICK * 10 ; rand_ray1[2][1] = TTICK ;
rand_ray2[0][0] = TTICK ; rand_ray2[0][1] = TTICK ;
rand_ray2[1][0] = TTICK ; rand_ray2[1][1] = TTICK * 10 ;
rand_ray2[2][0] = TTICK * 10 ; rand_ray2[2][1] = TTICK ;
/* Three triangles adjacent to the corners. RotLeft P(i)--> Q(i+1) */
rand_ray1[3][0] = TTICK * 2 ; rand_ray1[3][1] = TTICK * 2 ;
rand_ray1[4][0] = TTICK * 2 ; rand_ray1[4][1] = TTICK * 8 ;
rand_ray1[5][0] = TTICK * 8 ; rand_ray1[5][1] = TTICK * 2 ;
rand_ray2[4][0] = TTICK * 2 ; rand_ray2[4][1] = TTICK * 2 ;
rand_ray2[5][0] = TTICK * 2 ; rand_ray2[5][1] = TTICK * 8 ;
rand_ray2[3][0] = TTICK * 8 ; rand_ray2[3][1] = TTICK * 2 ;
/* Three triangles adjacent to the center. RotRight P(i)--> Q(i-1) */
rand_ray1[6][0] = TTICK * 2 ; rand_ray1[6][1] = TTICK * 5 ;
rand_ray1[7][0] = TTICK * 5 ; rand_ray1[7][1] = TTICK * 5 ;
rand_ray1[8][0] = TTICK * 5 ; rand_ray1[8][1] = TTICK * 2 ;
rand_ray2[8][0] = TTICK * 2 ; rand_ray2[8][1] = TTICK * 5 ;
rand_ray2[6][0] = TTICK * 5 ; rand_ray2[6][1] = TTICK * 5 ;
rand_ray2[7][0] = TTICK * 5 ; rand_ray2[7][1] = TTICK * 2 ;
/* Center triangle. Straight P(i) --> Q(i) */
rand_ray1[9][0] = TTICK * 4 ; rand_ray1[9][1] = TTICK * 4 ;
rand_ray2[9][0] = TTICK * 4 ; rand_ray2[9][1] = TTICK * 4 ;
/* Along the pelimeter. RotRight P(i)--> Q(i-1) */
rand_ray1[10][0] = TTICK * 1 ; rand_ray1[10][1] = TTICK * 7 ;
rand_ray1[11][0] = TTICK * 5 ; rand_ray1[11][1] = TTICK * 4 ;
rand_ray1[12][0] = TTICK * 4 ; rand_ray1[12][1] = TTICK * 1 ;
rand_ray2[12][0] = TTICK * 1 ; rand_ray2[12][1] = TTICK * 7 ;
rand_ray2[10][0] = TTICK * 5 ; rand_ray2[10][1] = TTICK * 4 ;
rand_ray2[11][0] = TTICK * 4 ; rand_ray2[11][1] = TTICK * 1 ;
/* Along the pelimeter. RotLeft P(i)--> Q(i+1) */
rand_ray1[13][0] = TTICK * 1 ; rand_ray1[13][1] = TTICK * 4 ;
rand_ray1[14][0] = TTICK * 4 ; rand_ray1[14][1] = TTICK * 7 ;
rand_ray1[15][0] = TTICK * 7 ; rand_ray1[15][1] = TTICK * 1 ;
rand_ray2[14][0] = TTICK * 1 ; rand_ray2[14][1] = TTICK * 4 ;
rand_ray2[15][0] = TTICK * 4 ; rand_ray2[15][1] = TTICK * 7 ;
rand_ray2[13][0] = TTICK * 7 ; rand_ray2[13][1] = TTICK * 1 ;
/* Initialize patch cache */
init_patch_cache(process_id) ;
}
/*************************************************************
*
* void get_test_ray(): get a randomized ray vector and start point.
*
* Place: main loop.
*
* Storage: must keep in the invidiual processor.
*
*************************************************************/
void get_test_rays(Vertex *p_src, Ray *v, long no, long process_id)
{
long g_index, i ;
Vertex p_dst ;
float fv1, fv2 ;
if( no > VISI_RAYS_MAX )
no = VISI_RAYS_MAX ;
for (i = 0, g_index = 0 ; i < no; i++, g_index++) {
fv1 = rand_ray1[ g_index ][0] ;
fv2 = rand_ray1[ g_index ][1] ;
p_src->x = vis_struct[process_id].v_src_p1.x + vis_struct[process_id].v_src_v12.x * fv1 + vis_struct[process_id].v_src_v13.x * fv2 ;
p_src->y = vis_struct[process_id].v_src_p1.y + vis_struct[process_id].v_src_v12.y * fv1 + vis_struct[process_id].v_src_v13.y * fv2 ;
p_src->z = vis_struct[process_id].v_src_p1.z + vis_struct[process_id].v_src_v12.z * fv1 + vis_struct[process_id].v_src_v13.z * fv2 ;
fv1 = rand_ray2[ g_index ][0] ;
fv2 = rand_ray2[ g_index ][1] ;
p_dst.x = vis_struct[process_id].v_dest_p1.x + vis_struct[process_id].v_dest_v12.x * fv1 + vis_struct[process_id].v_dest_v13.x * fv2 ;
p_dst.y = vis_struct[process_id].v_dest_p1.y + vis_struct[process_id].v_dest_v12.y * fv1 + vis_struct[process_id].v_dest_v13.y * fv2 ;
p_dst.z = vis_struct[process_id].v_dest_p1.z + vis_struct[process_id].v_dest_v12.z * fv1 + vis_struct[process_id].v_dest_v13.z * fv2 ;
v->x = p_dst.x - p_src->x;
v->y = p_dst.y - p_src->y;
v->z = p_dst.z - p_src->z;
p_src++;
v++;
}
}
/************************************************************************
*
* long v_intersect(): check if the ray intersects with the polygon.
*
*************************************************************************/
long v_intersect(Patch *patch, Vertex *p, Ray *ray, float t)
{
float px, py, pz;
float nx, ny, nz;
float rx, ry, rz;
float x, y, x1, x2, x3, y1, y2, y3;
float a, b, c;
long nc, sh, nsh;
nx = patch->plane_equ.n.x;
ny = patch->plane_equ.n.y;
nz = patch->plane_equ.n.z;
rx = ray->x;
ry = ray->y;
rz = ray->z;
px = p->x;
py = p->y;
pz = p->z;
a = FABS(nx); b = FABS(ny); c = FABS(nz);
if (a > b)
if (a > c) {
x = py + t * ry; y = pz + t * rz;
x1 = patch->p1.y; y1 = patch->p1.z;
x2 = patch->p2.y; y2 = patch->p2.z;
x3 = patch->p3.y; y3 = patch->p3.z;
} else {
x = px + t * rx; y = py + t * ry;
x1 = patch->p1.x; y1 = patch->p1.y;
x2 = patch->p2.x; y2 = patch->p2.y;
x3 = patch->p3.x; y3 = patch->p3.y;
}
else if (b > c) {
x = px + t * rx; y = pz + t * rz;
x1 = patch->p1.x; y1 = patch->p1.z;
x2 = patch->p2.x; y2 = patch->p2.z;
x3 = patch->p3.x; y3 = patch->p3.z;
} else {
x = px + t * rx; y = py + t * ry;
x1 = patch->p1.x; y1 = patch->p1.y;
x2 = patch->p2.x; y2 = patch->p2.y;
x3 = patch->p3.x; y3 = patch->p3.y;
}
x1 -= x; y1 -= y;
x2 -= x; y2 -= y;
x3 -= x; y3 -= y;
nc = 0;
if (y1 >= 0.0)
sh = 1;
else
sh = -1;
if (y2 >= 0.0)
nsh = 1;
else
nsh = -1;
if (sh != nsh) {
if ((x1 >= 0.0) && (x2 >= 0.0))
nc++;
else if ((x1 >= 0.0) || (x2 >= 0.0))
if ((x1 - y1 * (x2 - x1) / (y2 - y1)) > 0.0)
nc++;
sh = nsh;
}
if (y3 >= 0.0)
nsh = 1;
else
nsh = -1;
if (sh != nsh) {
if ((x2 >= 0.0) && (x3 >= 0.0))
nc++;
else if ((x2 >= 0.0) || (x3 >= 0.0))
if ((x2 - y2 * (x3 - x2) / (y3 - y2)) > 0.0)
nc++;
sh = nsh;
}
if (y1 >= 0.0)
nsh = 1;
else
nsh = -1;
if (sh != nsh) {
if ((x3 >= 0.0) && (x1 >= 0.0))
nc++;
else if ((x3 >= 0.0) || (x1 >= 0.0))
if ((x1 - y1 * (x1 - x3) / (y1 - y3)) > 0.0)
nc++;
sh = nsh;
}
if ((nc % 2) == 0)
return(0);
else {
return(1);
}
}
#define DEST_FOUND (1)
#define DEST_NOT_FOUND (0)
#define ON_THE_PLANE (0)
#define POSITIVE_SUBTREE_ONLY (1)
#define NEGATIVE_SUBTREE_ONLY (2)
#define POSITIVE_SIDE_FIRST (3)
#define NEGATIVE_SIDE_FIRST (4)
/****************************************************************************
*
* traverse_bsp()
* traverse_subtree()
*
* Traverse the BSP tree. The traversal is in-order. Since the traversal
* of the BSP tree begins at the middle of the BSP tree (i.e., the source
* node), the traversal is performed as follows.
* 1) Traverse the positive subtee of the start (source) node.
* 2) For each ancestor node of the source node, visit it (immediate
* parent first).
* 2.1) Test if the node intercepts the ray.
* 2.2) Traverse the subtree of the node (i.e., the subtree that the
* source node does not belong to.
*
* traverse_bsp() takes care of the traversal of ancestor nodes. Ordinary
* traversal of a subtree is done by traverse_subtree().
*
*****************************************************************************/
long traverse_bsp(Patch *src_node, Vertex *p, Ray *ray, float r_min, float r_max, long process_id)
{
float t = 0.0 ;
Patch *parent, *visited_child ;
long advice ;
/* (1) Check patch cache */
if( check_patch_cache( p, ray, r_min, r_max, process_id ) )
return( 1 ) ;
/* (2) Check S+(src_node) */
if( traverse_subtree( src_node->bsp_positive, p, ray, r_min, r_max, process_id ) )
return( 1 ) ;
/* (3) Continue in-order traversal till root is encountered */
for( parent = src_node->bsp_parent, visited_child = src_node ;
parent ;
visited_child = parent, parent = parent->bsp_parent )
{
/* Check intersection at this node */
advice = intersection_type( parent, p, ray, &t, r_min, r_max ) ;
if( (advice != POSITIVE_SUBTREE_ONLY) && (advice != NEGATIVE_SUBTREE_ONLY) )
{
if( test_intersection( parent, p, ray, t, process_id ) )
return( 1 ) ;
r_min = t - VIS_RANGE_MARGIN ;
}
/* Traverse unvisited subtree of the node */
if( (parent->bsp_positive == visited_child) && (advice != POSITIVE_SUBTREE_ONLY) )
{
if( traverse_subtree( parent->bsp_negative, p, ray, r_min, r_max, process_id ) )
return( 1 ) ;
}
else if( (parent->bsp_positive != visited_child) && (advice != NEGATIVE_SUBTREE_ONLY) )
{
if( traverse_subtree( parent->bsp_positive, p, ray, r_min, r_max, process_id ) )
return( 1 ) ;
}
}
return( 0 ) ;
}
long traverse_subtree(Patch *node, Vertex *p, Ray *ray, float r_min, float r_max, long process_id)
/*
* To minimize the length of the traversal of the BSP tree, a pruning
* algorithm is incorporated.
* One possibility (not used in this version) is to prune one of the
* subtrees if the node in question intersects the ray outside of the
* range defined by the source and the destination patches.
* Another possibility (used here) is more aggressive pruning. Like the above
* method, the intersection point is checked against the range to prune the
* subtree. But instead of using a constant source-destination range,
* the range itself is recursively subdivided so that the minimum range is
* applied the possibility of pruning maximized.
*/
{
float t ;
long advice ;
if( node == 0 )
return( 0 ) ;
advice = intersection_type( node, p, ray, &t, r_min, r_max ) ;
if( advice == POSITIVE_SIDE_FIRST )
{
/* The ray is approaching from the positive side of the patch */
if( traverse_subtree( node->bsp_positive, p, ray,
r_min, t + VIS_RANGE_MARGIN, process_id ) )
return( 1 ) ;
if( test_intersection( node, p, ray, t, process_id ) )
return( 1 ) ;
return( traverse_subtree( node->bsp_negative, p, ray,
t - VIS_RANGE_MARGIN, r_max, process_id ) ) ;
}
else if( advice == NEGATIVE_SIDE_FIRST )
{
/* The ray is approaching from the negative side of the patch */
if( traverse_subtree( node->bsp_negative, p, ray,
r_min, t + VIS_RANGE_MARGIN, process_id ) )
return( 1 ) ;
if( test_intersection( node, p, ray, t, process_id ) )
return( 1 ) ;
return( traverse_subtree( node->bsp_positive, p, ray,
t - VIS_RANGE_MARGIN, r_max, process_id ) ) ;
}
else if( advice == POSITIVE_SUBTREE_ONLY )
return( traverse_subtree( node->bsp_positive, p, ray,
r_min, r_max, process_id ) ) ;
else if( advice == NEGATIVE_SUBTREE_ONLY )
return( traverse_subtree( node->bsp_negative, p, ray,
r_min, r_max, process_id ) ) ;
else
/* On the plane */
return( 1 ) ;
}
/**************************************************************************
*
* intersection_type()
*
* Compute intersection coordinate as the barycentric coordinate
* w.r.t the ray vector. This value is returned to the caller through
* the variable passed by reference.
* intersection_type() also classifies the intersection type and
* returns the type as the "traversal advice" code.
* Possible types are:
* 1) the patch and the ray are parallel
* --> POSITIVE_SUBTREE_ONLY, NEGATIVE_SUBTREE_ONLY, or ON_THE_PLANE
* 2) intersects the ray outside of the specified range
* --> POSITIVE_SUBTREE_ONLY, NEGATIVE_SUBTREE_ONLY
* 3) intersects within the range
* --> POSITIVE_SIDE_FIRST, NEGATIVE_SIDE_FIRST
*
***************************************************************************/
long intersection_type(Patch *patch, Vertex *p, Ray *ray, float *tval, float range_min, float range_max)
{
float r_dot_n ;
float dist ;
float t ;
float nx, ny, nz ;
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
vis_struct[process_id].bsp_nodes_visited++ ;
#endif
/* (R.N) */
nx = patch->plane_equ.n.x ;
ny = patch->plane_equ.n.y ;
nz = patch->plane_equ.n.z ;
r_dot_n = nx * ray->x + ny * ray->y + nz * ray->z ;
dist = patch->plane_equ.c + p->x * nx + p->y * ny + p->z * nz ;
if( (-(float)F_ZERO < r_dot_n) && (r_dot_n < (float)F_ZERO) )
{
if( dist > (float)F_COPLANAR )
return( POSITIVE_SUBTREE_ONLY ) ;
else if( dist < -F_COPLANAR )
return( NEGATIVE_SUBTREE_ONLY ) ;
return( ON_THE_PLANE ) ;
}
t = -dist / r_dot_n ;
*tval = t ;
if( t < range_min )
{
if( r_dot_n >= 0 )
return( POSITIVE_SUBTREE_ONLY ) ;
else
return( NEGATIVE_SUBTREE_ONLY ) ;
}
else if ( t > range_max )
{
if( r_dot_n >= 0 )
return( NEGATIVE_SUBTREE_ONLY ) ;
else
return( POSITIVE_SUBTREE_ONLY ) ;
}
else
{
if( r_dot_n >= 0 )
return( NEGATIVE_SIDE_FIRST ) ;
else
return( POSITIVE_SIDE_FIRST ) ;
}
}
/*************************************************************
*
* test_intersection()
*
*************************************************************/
long test_intersection(Patch *patch, Vertex *p, Ray *ray, float tval, long process_id)
{
/* Rays always hit the destination. Note that (R.Ndest) is already
checked by visibility() */
if( patch == vis_struct[process_id].v_dest_patch )
{
vis_struct[process_id].pool_dst_hits++ ;
return( 1 ) ;
}
if( patch_tested( patch, process_id ) )
return( 0 ) ;
if( v_intersect( patch, p, ray, tval ) )
{
/* Store it in the patch-cache */
update_patch_cache( patch, process_id ) ;
return( 1 ) ;
}
return( 0 ) ;
}
/*************************************************************
*
* patch_cache
*
* update_patch_cache()
* check_patch_cache()
* init_patch_cache()
*
* To exploit visibility coherency, a patch cache is used.
* Before traversing the BSP tree, the cache contents are tested to see
* if they intercept the ray in question. The size of the patch cache is
* defined by PATCH_CACHE_SIZE (in patch.H). Since the first two
* entries of the cache
* usually cover about 95% of the cache hits, increasing the cache size
* does not help much. Nevertheless, the program is written so that
* increasing cache size does not result in additional ray-intersection
* test.
*
*************************************************************/
void update_patch_cache(Patch *patch, long process_id)
{
long i ;
/* Shift current contents */
for( i = PATCH_CACHE_SIZE-1 ; i > 0 ; i-- )
vis_struct[process_id].patch_cache[i] = vis_struct[process_id].patch_cache[i-1] ;
/* Store the new patch data */
vis_struct[process_id].patch_cache[0] = patch ;
}
long check_patch_cache(Vertex *p, Ray *ray, float r_min, float r_max, long process_id)
{
long i ;
float t ;
Patch *temp ;
long advice ;
for( i = 0 ; i < PATCH_CACHE_SIZE ; i++ )
{
if( (vis_struct[process_id].patch_cache[i] == 0)
|| (vis_struct[process_id].patch_cache[i] == vis_struct[process_id].v_dest_patch)
|| (vis_struct[process_id].patch_cache[i] == vis_struct[process_id].v_src_patch) )
continue ;
advice = intersection_type( vis_struct[process_id].patch_cache[i], p, ray, &t, r_min, r_max ) ;
/* If no intersection, then skip */
if( (advice == POSITIVE_SUBTREE_ONLY)
|| (advice == NEGATIVE_SUBTREE_ONLY) )
continue ;
if( (advice == ON_THE_PLANE) || v_intersect( vis_struct[process_id].patch_cache[i], p, ray, t ) )
{
/* Change priority */
if( i > 0 )
{
temp = vis_struct[process_id].patch_cache[ i-1 ] ;
vis_struct[process_id].patch_cache[ i-1 ] = vis_struct[process_id].patch_cache[ i ] ;
vis_struct[process_id].patch_cache[ i ] = temp ;
}
return( 1 ) ;
}
}
return( 0 ) ;
}
void init_patch_cache(long process_id)
{
long i ;
for( i = 0 ; i < PATCH_CACHE_SIZE ; i++ )
vis_struct[process_id].patch_cache[ i ] = 0 ;
}
long patch_tested(Patch *p, long process_id)
{
long i ;
for( i = 0 ; i < PATCH_CACHE_SIZE ; i++ )
{
if( p == vis_struct[process_id].patch_cache[i] )
return( 1 ) ;
}
return( 0 ) ;
}
/*************************************************************
*
* float visibility(): checking if two patches are mutually invisible.
*
*************************************************************/
float visibility(Element *e1, Element *e2, long n_rays, long process_id)
{
float range_max, range_min ;
long i;
Ray *r;
long ray_reject ;
vis_struct[process_id].v_src_patch = e1->patch;
vis_struct[process_id].v_dest_patch = e2->patch;
vis_struct[process_id].v_src_p1 = e1->ev1->p ;
vis_struct[process_id].v_src_v12.x = e1->ev2->p.x - vis_struct[process_id].v_src_p1.x ;
vis_struct[process_id].v_src_v12.y = e1->ev2->p.y - vis_struct[process_id].v_src_p1.y ;
vis_struct[process_id].v_src_v12.z = e1->ev2->p.z - vis_struct[process_id].v_src_p1.z ;
vis_struct[process_id].v_src_v13.x = e1->ev3->p.x - vis_struct[process_id].v_src_p1.x ;
vis_struct[process_id].v_src_v13.y = e1->ev3->p.y - vis_struct[process_id].v_src_p1.y ;
vis_struct[process_id].v_src_v13.z = e1->ev3->p.z - vis_struct[process_id].v_src_p1.z ;
vis_struct[process_id].v_dest_p1 = e2->ev1->p ;
vis_struct[process_id].v_dest_v12.x = e2->ev2->p.x - vis_struct[process_id].v_dest_p1.x ;
vis_struct[process_id].v_dest_v12.y = e2->ev2->p.y - vis_struct[process_id].v_dest_p1.y ;
vis_struct[process_id].v_dest_v12.z = e2->ev2->p.z - vis_struct[process_id].v_dest_p1.z ;
vis_struct[process_id].v_dest_v13.x = e2->ev3->p.x - vis_struct[process_id].v_dest_p1.x ;
vis_struct[process_id].v_dest_v13.y = e2->ev3->p.y - vis_struct[process_id].v_dest_p1.y ;
vis_struct[process_id].v_dest_v13.z = e2->ev3->p.z - vis_struct[process_id].v_dest_p1.z ;
get_test_rays( vis_struct[process_id].point_pool, vis_struct[process_id].ray_pool, n_rays, process_id ) ;
range_min = -VIS_RANGE_MARGIN ;
range_max = 1.0 + VIS_RANGE_MARGIN ;
vis_struct[process_id].pool_dst_hits = 0 ;
ray_reject = 0 ;
for ( i = 0 ; i < n_rays ; i++ )
{
r = &(vis_struct[process_id].ray_pool[i]);
if ( (inner_product( (Vertex *)r, &(vis_struct[process_id].v_src_patch)->plane_equ.n ) <= 0.0 )
||(inner_product( (Vertex *)r, &(vis_struct[process_id].v_dest_patch)->plane_equ.n ) >= 0.0 ) )
{
ray_reject++ ;
continue ;
}
traverse_bsp( vis_struct[process_id].v_src_patch, &vis_struct[process_id].point_pool[i], r, range_min, range_max, process_id ) ;
}
if (ray_reject == n_rays) {
/* All rays have been trivially rejected. This can occur
if no rays are shot between visible portion of the elements.
Return partial visibility (1/No-of-rays). */
/* Return partially visible result */
vis_struct[process_id].pool_dst_hits = 1 ;
}
return( (float)vis_struct[process_id].pool_dst_hits / (float)n_rays ) ;
}
/*****************************************************************
*
* compute_visibility_values()
*
* Apply visibility() function to an interaction list.
*
******************************************************************/
void compute_visibility_values(Element *elem, Interaction *inter, long n_inter, long process_id)
{
for( ; n_inter > 0 ; inter = inter->next, n_inter-- )
{
if( inter->visibility != VISIBILITY_UNDEF )
continue ;
vis_struct[process_id].bsp_nodes_visited = 0 ;
inter->visibility
= visibility( elem, inter->destination,
N_VISIBILITY_TEST_RAYS, process_id ) ;
vis_struct[process_id].total_bsp_nodes_visited += vis_struct[process_id].bsp_nodes_visited ;
}
}
/*****************************************************************
*
* visibility_task()
*
* Compute visibility values and then call continuation when all
* the undefined visibility values have been computed.
*
******************************************************************/
void visibility_task(Element *elem, Interaction *inter, long n_inter, void (*k)(), long process_id)
{
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
Patch_Cost *pc ;
#endif
long new_vis_undef_count ;
/* Compute visibility */
vis_struct[process_id].total_bsp_nodes_visited = 0 ;
compute_visibility_values( elem, inter, n_inter, process_id ) ;
/* Change visibility undef count */
LOCK(elem->elem_lock->lock);
elem->n_vis_undef_inter -= n_inter ;
new_vis_undef_count = elem->n_vis_undef_inter ;
UNLOCK(elem->elem_lock->lock);
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
pc = &global->patch_cost[ elem->patch->seq_no ] ;
LOCK(pc->cost_lock->lock);
pc->n_bsp_node += vis_struct[process_id].total_bsp_nodes_visited ;
UNLOCK(pc->cost_lock->lock);
#endif
/* Call continuation if this is the last task finished. */
if( new_vis_undef_count == 0 )
k( elem, process_id ) ;
}