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