gem5/splash2/codes/apps/radiosity/visible.C
Sanchayan Maity 0f4b39775c Fix splash2 benchmark
During the last commit of splash2 benchmark it seems before committing
when we ran "make clean", it effectively undid what the patch at below
link did
http://www.capsl.udel.edu/splash/Download.html

Fix this since without this it is not possible to build the arcane
splash2 benchmark.
2017-04-26 21:33:02 +05:30

770 lines
26 KiB
C

/*************************************************************************/
/* */
/* 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 ) ;
}