1433 lines
47 KiB
C
1433 lines
47 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. */
|
|
/* */
|
|
/*************************************************************************/
|
|
|
|
/*
|
|
* Element management.
|
|
*
|
|
* This module has the following functionalities.
|
|
* (1) Creation/initialization of a new instance of an element object.
|
|
* (2) Recursive refinement of elements.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
EXTERN_ENV;
|
|
|
|
include(radiosity.h)
|
|
|
|
static void _foreach_element(Element *elem, void (*func)(), long arg1, long process_id);
|
|
static void _foreach_leaf_element(Element *elem, void (*func)(), long arg1, long process_id);
|
|
static long bf_refine_element(long subdiv, Element *elem, Interaction *inter, long process_id);
|
|
static void process_rays2(Element *e, long process_id);
|
|
static void process_rays3(Element *e, long process_id);
|
|
static void elem_join_operation(Element *e, Element *ec, long process_id);
|
|
static void gather_rays(Element *elem, long process_id);
|
|
static float _diff_disc_formfactor(Vertex *p, Element *e_src, Vertex *p_disc, float area, Vertex *normal, long process_id);
|
|
static float compute_diff_disc_formfactor(Vertex *p, Element *e_src, Vertex *p_disc, Element *e_dst, long process_id);
|
|
|
|
/***************************************************************************
|
|
****************************************************************************
|
|
*
|
|
* Methods for Element object
|
|
*
|
|
****************************************************************************
|
|
****************************************************************************
|
|
****************************************************************************
|
|
*
|
|
* foreach_element_in_patch()
|
|
* foreach_leaf_element_in_patch()
|
|
*
|
|
* General purpose driver. For each element of a patch, apply specified
|
|
* function. The function is passed a pointer to the element.
|
|
* Traversal is DFS (post-order).
|
|
*
|
|
****************************************************************************/
|
|
|
|
void foreach_element_in_patch(Patch *patch, void (*func)(), long arg1, long process_id)
|
|
{
|
|
_foreach_element( patch->el_root, func, arg1, process_id ) ;
|
|
}
|
|
|
|
|
|
static void _foreach_element(Element *elem, void (*func)(), long arg1, long process_id)
|
|
{
|
|
if( elem == 0 )
|
|
return ;
|
|
|
|
/* Process children */
|
|
if( ! LEAF_ELEMENT( elem ) )
|
|
{
|
|
_foreach_element( elem->center, func, arg1, process_id ) ;
|
|
_foreach_element( elem->top, func, arg1, process_id ) ;
|
|
_foreach_element( elem->left, func, arg1, process_id ) ;
|
|
_foreach_element( elem->right, func, arg1, process_id ) ;
|
|
}
|
|
|
|
/* Apply function to this node */
|
|
func( elem, arg1, process_id ) ;
|
|
}
|
|
|
|
|
|
void foreach_leaf_element_in_patch(Patch *patch, void (*func)(), long arg1, long process_id)
|
|
{
|
|
_foreach_leaf_element( patch->el_root, func, arg1, process_id ) ;
|
|
}
|
|
|
|
|
|
static void _foreach_leaf_element(Element *elem, void (*func)(), long arg1, long process_id )
|
|
{
|
|
if( elem == 0 )
|
|
return ;
|
|
|
|
/* Process children */
|
|
if( LEAF_ELEMENT( elem ) )
|
|
func( elem, arg1, process_id ) ;
|
|
else
|
|
{
|
|
_foreach_leaf_element( elem->center, func, arg1, process_id ) ;
|
|
_foreach_leaf_element( elem->top, func, arg1, process_id ) ;
|
|
_foreach_leaf_element( elem->left, func, arg1, process_id ) ;
|
|
_foreach_leaf_element( elem->right, func, arg1, process_id ) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* ff_refine_elements()
|
|
*
|
|
* Recursively refine the elements based on FF estimate.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void ff_refine_elements(Element *e1, Element *e2, long level, long process_id)
|
|
{
|
|
long subdiv_advice ;
|
|
Interaction i12, i21 ;
|
|
Interaction *inter ;
|
|
|
|
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
|
|
#if defined(SUN4)
|
|
Patch_Cost *pc1, *pc2 ;
|
|
#else
|
|
volatile Patch_Cost *pc1, *pc2 ;
|
|
#endif
|
|
long cost1, cost2 ;
|
|
#endif
|
|
|
|
|
|
/* Now compute formfactor.
|
|
As the BSP tree is being modified at this moment, don't test
|
|
visibility. */
|
|
compute_formfactor( e1, e2, &i12, process_id ) ;
|
|
compute_formfactor( e2, e1, &i21, process_id ) ;
|
|
|
|
/* Analyze the error of FF */
|
|
subdiv_advice = error_analysis( e1, e2, &i12, &i21, process_id ) ;
|
|
|
|
/* Execute subdivision procedure */
|
|
if( NO_INTERACTION(subdiv_advice) )
|
|
/* Two elements are mutually invisible. Do nothing */
|
|
return ;
|
|
|
|
else if( NO_REFINEMENT_NECESSARY(subdiv_advice) )
|
|
{
|
|
/* Create links and finish the job */
|
|
inter = get_interaction(process_id) ;
|
|
*inter = i12 ;
|
|
inter->visibility = VISIBILITY_UNDEF ;
|
|
insert_vis_undef_interaction( e1, inter, process_id ) ;
|
|
|
|
inter = get_interaction(process_id) ;
|
|
*inter = i21 ;
|
|
inter->visibility = VISIBILITY_UNDEF ;
|
|
insert_vis_undef_interaction( e2, inter, process_id ) ;
|
|
|
|
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
|
|
/* Update cost variable */
|
|
pc1 = &global->patch_cost[ e1->patch->seq_no ] ;
|
|
pc2 = &global->patch_cost[ e2->patch->seq_no ] ;
|
|
if( pc1->n_total_inter <= 13 )
|
|
cost1 = (long)ceil(e1->area / Area_epsilon) ;
|
|
else
|
|
cost1 = 1 ;
|
|
|
|
if( pc2->n_total_inter <= 13 )
|
|
cost2 = (long)ceil(e2->area / Area_epsilon) ;
|
|
else
|
|
cost2 = 1 ;
|
|
|
|
LOCK(global->cost_sum_lock);
|
|
pc1->cost_estimate += cost1 ;
|
|
pc1->n_total_inter++ ;
|
|
pc2->cost_estimate += cost2 ;
|
|
pc2->n_total_inter++ ;
|
|
global->cost_estimate_sum += (cost1 + cost2) ;
|
|
global->cost_sum += (cost1 + cost2) ;
|
|
UNLOCK(global->cost_sum_lock);
|
|
#endif
|
|
}
|
|
|
|
else if( REFINE_PATCH_1(subdiv_advice) )
|
|
{
|
|
/* Refine patch 1 */
|
|
subdivide_element( e1, process_id ) ;
|
|
|
|
/* Locally solve it */
|
|
ff_refine_elements( e1->top, e2, level+1, process_id ) ;
|
|
ff_refine_elements( e1->center, e2, level+1, process_id ) ;
|
|
ff_refine_elements( e1->left, e2, level+1, process_id ) ;
|
|
ff_refine_elements( e1->right, e2, level+1, process_id ) ;
|
|
}
|
|
else
|
|
{
|
|
/* Refine patch 2 */
|
|
subdivide_element( e2, process_id ) ;
|
|
|
|
/* Locally solve it */
|
|
ff_refine_elements( e1, e2->top, level+1, process_id ) ;
|
|
ff_refine_elements( e1, e2->center, level+1, process_id ) ;
|
|
ff_refine_elements( e1, e2->left, level+1, process_id ) ;
|
|
ff_refine_elements( e1, e2->right, level+1, process_id ) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* error_analysis()
|
|
*
|
|
* Analyze FF error.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long error_analysis(Element *e1, Element *e2, Interaction *inter12, Interaction *inter21, long process_id)
|
|
{
|
|
long cc ;
|
|
|
|
/* Check visibility */
|
|
cc = patch_intersection( &e1->patch->plane_equ,
|
|
&e2->ev1->p, &e2->ev2->p, &e2->ev3->p, process_id ) ;
|
|
if( NEGATIVE_SIDE(cc) )
|
|
/* If negative or on the plane, then do nothing */
|
|
return( _NO_INTERACTION ) ;
|
|
|
|
cc = patch_intersection( &e2->patch->plane_equ,
|
|
&e1->ev1->p, &e1->ev2->p, &e1->ev3->p, process_id ) ;
|
|
if( NEGATIVE_SIDE(cc) )
|
|
/* If negative or on the plane, then do nothing */
|
|
return( _NO_INTERACTION ) ;
|
|
|
|
return( _NO_REFINEMENT_NECESSARY ) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* bf_refine_element()
|
|
*
|
|
* Recursively refine the elements based on BF estimate.
|
|
* Return value: number of interactions newly created.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static long bf_refine_element(long subdiv, Element *elem, Interaction *inter, long process_id)
|
|
{
|
|
Element *e_dst = inter->destination ;
|
|
Interaction *pi ;
|
|
float visibility_val ;
|
|
long new_inter = 0 ;
|
|
|
|
|
|
visibility_val = NO_VISIBILITY_NECESSARY(subdiv)?
|
|
(float)1.0 : VISIBILITY_UNDEF ;
|
|
|
|
if( REFINE_PATCH_1(subdiv) )
|
|
{
|
|
/* Refine this element */
|
|
/* (1) Make sure it has children */
|
|
subdivide_element( elem, process_id ) ;
|
|
|
|
/* (2) For each of the patch, create an interaction */
|
|
if( element_completely_invisible( elem->center, e_dst, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem->center, e_dst, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem->center, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
if( element_completely_invisible( elem->top, e_dst, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem->top, e_dst, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem->top, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
if( element_completely_invisible( elem->left, e_dst, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem->left, e_dst, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem->left, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
if( element_completely_invisible( elem->right, e_dst, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem->right, e_dst, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem->right, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Refine source element */
|
|
/* (1) Make sure it has children */
|
|
subdivide_element( e_dst, process_id ) ;
|
|
|
|
/* (2) Insert four new interactions
|
|
NOTE: Use *inter as a place holder to link 4 new interactions
|
|
since *prev may be NULL */
|
|
|
|
if( element_completely_invisible( elem, e_dst->center, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem, e_dst->center, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
if( element_completely_invisible( elem, e_dst->top, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem, e_dst->top, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
if( element_completely_invisible( elem, e_dst->left, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem, e_dst->left, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
if( element_completely_invisible( elem, e_dst->right, process_id ) == 0 )
|
|
{
|
|
pi = get_interaction(process_id) ;
|
|
compute_formfactor( elem, e_dst->right, pi, process_id ) ;
|
|
pi->visibility = visibility_val ;
|
|
insert_vis_undef_interaction( elem, pi, process_id ) ;
|
|
new_inter++ ;
|
|
}
|
|
}
|
|
|
|
return( new_inter ) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* bf_error_analysis_list()
|
|
*
|
|
* For each interaction in the list, analyze error of BF value.
|
|
* If error is lower than the limit, the interaction is linked to the
|
|
* normal interaction list. Otherwise, BF-refinement is performed and
|
|
* the newly created interactions are linked to the vis-undef-list.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void bf_error_analysis_list(Element *elem, Interaction *i_list, long process_id)
|
|
{
|
|
long subdiv_advice ;
|
|
Interaction *prev = 0 ;
|
|
Interaction *inter = i_list ;
|
|
Interaction *refine_inter ;
|
|
long i_len = 0 ;
|
|
long delta_n_inter = 0 ;
|
|
|
|
|
|
while( inter )
|
|
{
|
|
/* Analyze error */
|
|
subdiv_advice = bf_error_analysis( elem, inter, process_id ) ;
|
|
|
|
if( NO_REFINEMENT_NECESSARY(subdiv_advice) )
|
|
{
|
|
/* Go on to the next interaction */
|
|
prev = inter ;
|
|
inter = inter->next ;
|
|
i_len++ ;
|
|
}
|
|
else
|
|
{
|
|
/* Remove this interaction from the list */
|
|
refine_inter = inter ;
|
|
inter = inter->next ;
|
|
if( prev == 0 )
|
|
i_list = inter ;
|
|
else
|
|
prev->next = inter ;
|
|
|
|
/* Perform refine */
|
|
delta_n_inter += bf_refine_element( subdiv_advice,
|
|
elem, refine_inter, process_id ) ;
|
|
|
|
/* Delete this inter anyway */
|
|
free_interaction( refine_inter, process_id ) ;
|
|
delta_n_inter-- ;
|
|
}
|
|
}
|
|
|
|
/* Link good interactions to elem->intearctions */
|
|
if( i_len > 0 )
|
|
{
|
|
LOCK(elem->elem_lock->lock);
|
|
prev->next = elem->interactions ;
|
|
elem->interactions = i_list ;
|
|
elem->n_interactions += i_len ;
|
|
UNLOCK(elem->elem_lock->lock);
|
|
}
|
|
|
|
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
|
|
/* Update patch interaction count */
|
|
if( delta_n_inter != 0 )
|
|
{
|
|
Patch_Cost *pc ;
|
|
|
|
pc = &global->patch_cost[ elem->patch->seq_no ] ;
|
|
LOCK(pc->cost_lock->lock);
|
|
pc->n_total_inter += delta_n_inter ;
|
|
UNLOCK(pc->cost_lock->lock);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* bf_error_analysis()
|
|
*
|
|
* Analyze error of BF value.
|
|
* Return value: subdivision advice code.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long bf_error_analysis(Element *elem, Interaction *inter, long process_id)
|
|
{
|
|
float rad_avg ; /* Average radiosity */
|
|
float total_error ;
|
|
float visibility_error ;
|
|
long vis_code = 0 ;
|
|
|
|
/* Compute amount of error associated with the BF.
|
|
|
|
FFcomputed = (F + Ferr)(V + Verr) = FV + (Ferr V + F Verr + Ferr Verr)
|
|
BFcomputed = BF + BFerr
|
|
= B FV + B (Ferr V + F Verr + Ferr Verr)
|
|
*/
|
|
|
|
if( (0.0 < inter->visibility) && (inter->visibility < 1.0) )
|
|
visibility_error = 1.0 ;
|
|
else
|
|
visibility_error = FF_VISIBILITY_ERROR ;
|
|
|
|
rad_avg =( inter->destination->rad.r
|
|
+ inter->destination->rad.g
|
|
+ inter->destination->rad.b ) * (float)(1.0 / 3.0) ;
|
|
|
|
total_error = (inter->visibility * inter->formfactor_err
|
|
+ visibility_error * inter->formfactor_out
|
|
+ visibility_error * inter->formfactor_err) * rad_avg ;
|
|
|
|
/* If BF is smaller than the threshold, then not subdivide */
|
|
if( (total_error <= BFepsilon) && (elem->n_interactions <= 10) )
|
|
return( _NO_REFINEMENT_NECESSARY ) ;
|
|
else if( total_error <= BFepsilon * 0.5 )
|
|
return( _NO_REFINEMENT_NECESSARY ) ;
|
|
|
|
/* Subdivide light source or receiver whichever is larger */
|
|
if( elem->area > inter->destination->area )
|
|
{
|
|
if( elem->area > Area_epsilon )
|
|
/* Subdivide this element (receiver) */
|
|
return( _REFINE_PATCH_1 | vis_code ) ;
|
|
}
|
|
else
|
|
{
|
|
if( inter->destination->area > Area_epsilon )
|
|
|
|
/* Subdivide source element */
|
|
return( _REFINE_PATCH_2 | vis_code ) ;
|
|
}
|
|
|
|
return( _NO_REFINEMENT_NECESSARY ) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* radiosity_converged()
|
|
*
|
|
* Return TRUE(1) when the average radiosity value is converged.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long radiosity_converged(long process_id)
|
|
{
|
|
float prev_total, current_total ;
|
|
float difference ;
|
|
Rgb rad ;
|
|
|
|
/* Check radiosity value */
|
|
prev_total = global->prev_total_energy.r + global->prev_total_energy.g
|
|
+ global->prev_total_energy.b ;
|
|
current_total = global->total_energy.r + global->total_energy.g
|
|
+ global->total_energy.b ;
|
|
|
|
/* Compute difference from the previous iteration */
|
|
prev_total += 1.0e-4 ;
|
|
difference = fabs( (current_total / prev_total) - (float)1.0 ) ;
|
|
|
|
if( verbose_mode )
|
|
{
|
|
rad = global->total_energy ;
|
|
rad.r /= global->total_patch_area ;
|
|
rad.g /= global->total_patch_area ;
|
|
rad.b /= global->total_patch_area ;
|
|
printf( "Total energy: " ) ;
|
|
print_rgb( &global->total_energy ) ;
|
|
printf( "Average radiosity:" ) ;
|
|
print_rgb( &rad ) ;
|
|
printf( "Difference %.2f%%\n", difference * 100.0 ) ;
|
|
}
|
|
|
|
if( difference <= Energy_epsilon )
|
|
return( 1 ) ;
|
|
else
|
|
return( 0 ) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* subdivide_element()
|
|
*
|
|
* Create child elements. If they already exist, do nothing.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void subdivide_element(Element *e, long process_id)
|
|
{
|
|
float quarter_area ;
|
|
ElemVertex *ev_12, *ev_23, *ev_31 ;
|
|
Edge *e_12_23, *e_23_31, *e_31_12 ;
|
|
Element *enew, *ecenter ;
|
|
long rev_12, rev_23, rev_31 ;
|
|
|
|
/* Lock the element before checking the value */
|
|
LOCK(e->elem_lock->lock);
|
|
|
|
/* Check if the element already has children */
|
|
if( ! _LEAF_ELEMENT(e) )
|
|
{
|
|
UNLOCK(e->elem_lock->lock);
|
|
return ;
|
|
}
|
|
|
|
/* Subdivide edge structures */
|
|
subdivide_edge( e->e12, (float)0.5, process_id ) ;
|
|
subdivide_edge( e->e23, (float)0.5, process_id ) ;
|
|
subdivide_edge( e->e31, (float)0.5, process_id ) ;
|
|
ev_12 = e->e12->ea->pb ;
|
|
ev_23 = e->e23->ea->pb ;
|
|
ev_31 = e->e31->ea->pb ;
|
|
|
|
/* Then create new edges */
|
|
e_12_23 = create_edge( ev_12, ev_23, process_id ) ;
|
|
e_23_31 = create_edge( ev_23, ev_31, process_id ) ;
|
|
e_31_12 = create_edge( ev_31, ev_12, process_id ) ;
|
|
|
|
/* Area parameters */
|
|
quarter_area = e->area * (float)0.25 ;
|
|
|
|
/* (1) Create the center patch */
|
|
enew = get_element(process_id) ;
|
|
ecenter = enew ;
|
|
enew->parent= e ;
|
|
enew->patch = e->patch ;
|
|
enew->ev1 = ev_23 ;
|
|
enew->ev2 = ev_31 ;
|
|
enew->ev3 = ev_12 ;
|
|
enew->e12 = e_23_31 ;
|
|
enew->e23 = e_31_12 ;
|
|
enew->e31 = e_12_23 ;
|
|
enew->area = quarter_area ;
|
|
enew->rad = e->rad ;
|
|
|
|
/* (2) Create the top patch */
|
|
rev_12 = EDGE_REVERSE( e->e12, e->ev1, e->ev2 ) ;
|
|
rev_23 = EDGE_REVERSE( e->e23, e->ev2, e->ev3 ) ;
|
|
rev_31 = EDGE_REVERSE( e->e31, e->ev3, e->ev1 ) ;
|
|
|
|
enew = get_element(process_id) ;
|
|
e->top = enew ;
|
|
enew->parent= e ;
|
|
enew->patch = e->patch ;
|
|
enew->ev1 = e->ev1 ;
|
|
enew->ev2 = ev_12 ;
|
|
enew->ev3 = ev_31 ;
|
|
enew->e12 = (!rev_12)? e->e12->ea : e->e12->eb ;
|
|
enew->e23 = e_31_12 ;
|
|
enew->e31 = (!rev_31)? e->e31->eb : e->e31->ea ;
|
|
enew->area = quarter_area ;
|
|
enew->rad = e->rad ;
|
|
|
|
/* (3) Create the left patch */
|
|
enew = get_element(process_id) ;
|
|
e->left = enew ;
|
|
enew->parent= e ;
|
|
enew->patch = e->patch ;
|
|
enew->ev1 = ev_12 ;
|
|
enew->ev2 = e->ev2 ;
|
|
enew->ev3 = ev_23 ;
|
|
enew->e12 = (!rev_12)? e->e12->eb : e->e12->ea ;
|
|
enew->e23 = (!rev_23)? e->e23->ea : e->e23->eb ;
|
|
enew->e31 = e_12_23 ;
|
|
enew->area = quarter_area ;
|
|
enew->rad = e->rad ;
|
|
|
|
/* (4) Create the right patch */
|
|
enew = get_element(process_id) ;
|
|
e->right = enew ;
|
|
enew->parent= e ;
|
|
enew->patch = e->patch ;
|
|
enew->ev1 = ev_31 ;
|
|
enew->ev2 = ev_23 ;
|
|
enew->ev3 = e->ev3 ;
|
|
enew->e12 = e_23_31 ;
|
|
enew->e23 = (!rev_23)? e->e23->eb : e->e23->ea ;
|
|
enew->e31 = (!rev_31)? e->e31->ea : e->e31->eb ;
|
|
enew->area = quarter_area ;
|
|
enew->rad = e->rad ;
|
|
|
|
/* Finally, set e->center */
|
|
e->center = ecenter ;
|
|
|
|
/* Unlock the element */
|
|
UNLOCK(e->elem_lock->lock);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* process_rays()
|
|
*
|
|
* Gather rays.
|
|
*
|
|
* Solution strategy:
|
|
* Original radiosity equation: [I-M] B = E
|
|
* Iterative solution: 2 3
|
|
* B = [I + M + M + M ...] E
|
|
* Sollution by this routine: Bn = E + M Bn-1
|
|
* (B0 = E)
|
|
*
|
|
*
|
|
* process_rays() first checks the amount of error associated with each
|
|
* interaction. If it is large, then the interaction is refined.
|
|
* After all the interactions are examined, the light energy is
|
|
* gathered. This gathered energy and the energy passed from the ancestors
|
|
* are added and pushed down to descendants. The descendants in turn pop up
|
|
* the area weighted energy gathered at descendant level. Thus, the
|
|
* radiosity at level i is:
|
|
* Bi = E
|
|
* + Sum(j=0 to i-1) gather(j) --- gathered at ancestors
|
|
* + gather(i) --- gathered at this level
|
|
* + 1/4( Bi+1.right + Bi+1.left + Bi+1.top + Bi+1.center)
|
|
* --- gathered at descendants
|
|
*
|
|
* The implementation is slightly complicated due to many fork and join
|
|
* operations that occur when:
|
|
* (1) four children are visited and the results are added to Bi.
|
|
* (2) parallel visibility computation is done and then process_rays() resumed.
|
|
*
|
|
* The former case would be a simple (non-tail)-recursive code in a
|
|
* uniprocessor program. However, because we create tasks to process lower
|
|
* levels and the creation of tasks does not mean the completion of
|
|
* processing at the lower level, we use a mechanism to suspend
|
|
* processing at this level and later resume it after the child tasks are
|
|
* finished.
|
|
* To be portable across many systems, in this implementation procedures
|
|
* are split at the point of task creation so that the subtask can call
|
|
* the next portion of the procedure on exit of the task.
|
|
* This mechanism can be best explained as the continuation-passing-style
|
|
* (CPS) where continuation means a lambda expression which represents 'the
|
|
* rest of the program'.
|
|
*
|
|
****************************************************************************/
|
|
|
|
|
|
void process_rays(Element *e, long process_id)
|
|
{
|
|
Interaction *i_list ;
|
|
|
|
/* Detach interactions from the list */
|
|
LOCK(e->elem_lock->lock);
|
|
i_list = e->interactions ;
|
|
e->interactions = (Interaction *)0 ;
|
|
e->n_interactions = 0 ;
|
|
UNLOCK(e->elem_lock->lock);
|
|
|
|
/* For each interaction, do BF-error-analysis */
|
|
bf_error_analysis_list( e, i_list, process_id ) ;
|
|
|
|
if( e->n_vis_undef_inter == 0 )
|
|
process_rays3( e, process_id ) ;
|
|
else
|
|
/* Some interactions were refined.
|
|
Compute visibility and do BF-analysis again */
|
|
create_visibility_tasks( e, process_rays2, process_id ) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
static void process_rays2(Element *e, long process_id)
|
|
{
|
|
Interaction *i_list ;
|
|
|
|
/* Detach interactions from the vis-undef-list. They now have their
|
|
visibility computed */
|
|
LOCK(e->elem_lock->lock);
|
|
i_list = e->vis_undef_inter ;
|
|
e->vis_undef_inter = (Interaction *)0 ;
|
|
e->n_vis_undef_inter = 0 ;
|
|
UNLOCK(e->elem_lock->lock);
|
|
|
|
/* For each interaction, do BF-error-analysis */
|
|
bf_error_analysis_list( e, i_list, process_id ) ;
|
|
|
|
if( e->n_vis_undef_inter == 0 )
|
|
process_rays3( e, process_id ) ;
|
|
else
|
|
/* Some interactions were refined.
|
|
Compute visibility and do BF-analysis again */
|
|
create_visibility_tasks( e, process_rays2, process_id ) ;
|
|
}
|
|
|
|
|
|
|
|
static void process_rays3(Element *e, long process_id)
|
|
{
|
|
Rgb rad_push ; /* Radiosity value pushed down */
|
|
|
|
|
|
/* Gather light rays that impinge on this element */
|
|
gather_rays( e, process_id ) ;
|
|
|
|
/* Now visit children */
|
|
if( ! LEAF_ELEMENT(e) )
|
|
{
|
|
/* Compute radiosity that is pushed to descendents */
|
|
rad_push.r = e->rad_in.r + e->rad_subtree.r ;
|
|
rad_push.g = e->rad_in.g + e->rad_subtree.g ;
|
|
rad_push.b = e->rad_in.b + e->rad_subtree.b ;
|
|
|
|
e->center->rad_in = rad_push ;
|
|
e->top-> rad_in = rad_push ;
|
|
e->right-> rad_in = rad_push ;
|
|
e->left-> rad_in = rad_push ;
|
|
e->join_counter = 4 ;
|
|
|
|
/* Create tasks to process children */
|
|
create_ray_task( e->center, process_id ) ;
|
|
create_ray_task( e->top, process_id ) ;
|
|
create_ray_task( e->left, process_id ) ;
|
|
create_ray_task( e->right, process_id ) ;
|
|
|
|
/* The rest of the job (pop up the computed radiosity) is
|
|
handled by the continuation function, elem_join_operation().
|
|
It is called when the lower level finishes.
|
|
On exit, elem_join_operation() calls the continuation of the
|
|
parent, which is also elem_join_operation().
|
|
To be general, those tasks should be passed the continuation
|
|
(elem_join_operation). But, since the continuation is obvious
|
|
in this context, it is hardwired below */
|
|
}
|
|
else
|
|
{
|
|
/* Update element radiosity at the leaf level */
|
|
e->rad.r = e->rad_in.r + e->rad_subtree.r + e->patch->emittance.r ;
|
|
e->rad.g = e->rad_in.g + e->rad_subtree.g + e->patch->emittance.g ;
|
|
e->rad.b = e->rad_in.b + e->rad_subtree.b + e->patch->emittance.b ;
|
|
|
|
/* Ship out radiosity to the parent */
|
|
elem_join_operation( e->parent, e, process_id ) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* elem_join_operation()
|
|
*
|
|
* This function performs the second half of the function of process_rays.
|
|
* That is, i) add area weighted child radiosity
|
|
* ii) update radiosity variable
|
|
* iii) call continuation of the parent (ie, elem_join_operation
|
|
* itself)
|
|
*
|
|
* Thus, in spirit, the function is a tail recursive routine although
|
|
* tail-recursion-elimination is manually performed in the code below.
|
|
*
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void elem_join_operation(Element *e, Element *ec, long process_id)
|
|
{
|
|
long join_flag ;
|
|
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
|
|
Patch_Cost *pc ;
|
|
#endif
|
|
|
|
|
|
while( e != 0 )
|
|
{
|
|
/* Get radiosity of the child and add to my radiosity */
|
|
LOCK(e->elem_lock->lock);
|
|
e->rad_subtree.r += ec->rad_subtree.r * (float)0.25 ;
|
|
e->rad_subtree.g += ec->rad_subtree.g * (float)0.25 ;
|
|
e->rad_subtree.b += ec->rad_subtree.b * (float)0.25 ;
|
|
e->join_counter-- ;
|
|
join_flag = (e->join_counter == 0) ;
|
|
UNLOCK(e->elem_lock->lock);
|
|
|
|
if( join_flag == 0 )
|
|
/* Other children are not finished. Return. */
|
|
return ;
|
|
|
|
/* This is the continuation called by the last (4th) subprocess.
|
|
Perform JOIN at this level */
|
|
/* Update element radiosity */
|
|
e->rad.r = e->rad_in.r + e->rad_subtree.r + e->patch->emittance.r ;
|
|
e->rad.g = e->rad_in.g + e->rad_subtree.g + e->patch->emittance.g ;
|
|
e->rad.b = e->rad_in.b + e->rad_subtree.b + e->patch->emittance.b ;
|
|
|
|
/* Traverse the tree one level up and repeat */
|
|
ec = e ;
|
|
e = e->parent ;
|
|
}
|
|
|
|
/* Process RAY root level finished. Update energy variable */
|
|
LOCK(global->avg_radiosity_lock);
|
|
global->total_energy.r += ec->rad.r * ec->area ;
|
|
global->total_energy.g += ec->rad.g * ec->area ;
|
|
global->total_energy.b += ec->rad.b * ec->area ;
|
|
global->total_patch_area += ec->area ;
|
|
UNLOCK(global->avg_radiosity_lock);
|
|
|
|
#if PATCH_ASSIGNMENT == PATCH_ASSIGNMENT_COSTBASED
|
|
/* Then update the cost variable of the patch */
|
|
pc = &global->patch_cost[ ec->patch->seq_no ] ;
|
|
pc->cost_history[3] = pc->cost_history[2] ;
|
|
pc->cost_history[2] = pc->cost_history[1] ;
|
|
pc->cost_history[1] = pc->cost_history[0] ;
|
|
pc->cost_history[0] = PATCH_COST( pc ) ;
|
|
pc->cost_estimate = PATCH_COST_ESTIMATE( pc ) ;
|
|
|
|
/* Also, update the global cost variable */
|
|
LOCK(global->cost_sum_lock);
|
|
global->cost_sum += pc->cost_history[0] ;
|
|
global->cost_estimate_sum += pc->cost_estimate ;
|
|
UNLOCK(global->cost_sum_lock);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* gather_rays()
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void gather_rays(Element *elem, long process_id)
|
|
{
|
|
Rgb rad_elem ; /* Radiosity gathered by this elem */
|
|
float ff_v ; /* Form factor times visibility */
|
|
float bf_r, bf_g, bf_b ;
|
|
Interaction *inter ;
|
|
|
|
|
|
/* Return immediately if there is no interaction */
|
|
if( (inter = elem->interactions) == 0 )
|
|
{
|
|
elem->rad_subtree.r = 0.0 ;
|
|
elem->rad_subtree.g = 0.0 ;
|
|
elem->rad_subtree.b = 0.0 ;
|
|
return ;
|
|
}
|
|
|
|
|
|
/* Gather rays of this element
|
|
(do it directly without the driver function, 'Foreach-interaction') */
|
|
rad_elem.r = 0.0 ;
|
|
rad_elem.g = 0.0 ;
|
|
rad_elem.b = 0.0 ;
|
|
|
|
while( inter )
|
|
{
|
|
/* Be careful !
|
|
Use FF(out) to compute incoming energy */
|
|
ff_v = inter->formfactor_out * inter->visibility ;
|
|
bf_r = ff_v * inter->destination->rad.r ;
|
|
bf_g = ff_v * inter->destination->rad.g ;
|
|
bf_b = ff_v * inter->destination->rad.b ;
|
|
|
|
rad_elem.r += bf_r ;
|
|
rad_elem.g += bf_g ;
|
|
rad_elem.b += bf_b ;
|
|
|
|
/* Update pointers */
|
|
inter = inter->next ;
|
|
}
|
|
|
|
/* Multiply the gathered radiosity by the diffuse color of this element */
|
|
rad_elem.r *= elem->patch->color.r ;
|
|
rad_elem.g *= elem->patch->color.g ;
|
|
rad_elem.b *= elem->patch->color.b ;
|
|
|
|
/* Store the value at the initial value of 'rad_subtree' */
|
|
elem->rad_subtree = rad_elem ;
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* elememnt_completely_invisible()
|
|
*
|
|
* Fast primary visibility test.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long element_completely_invisible(Element *e1, Element *e2, long process_id)
|
|
{
|
|
long cc ;
|
|
|
|
/* Check visibility */
|
|
cc = patch_intersection( &e1->patch->plane_equ,
|
|
&e2->ev1->p, &e2->ev2->p, &e2->ev3->p, process_id ) ;
|
|
if( NEGATIVE_SIDE(cc) )
|
|
/* If negative or on the plane, then do nothing */
|
|
return( 1 ) ;
|
|
|
|
cc = patch_intersection( &e2->patch->plane_equ,
|
|
&e1->ev1->p, &e1->ev2->p, &e1->ev3->p, process_id ) ;
|
|
if( NEGATIVE_SIDE(cc) )
|
|
/* If negative or on the plane, then do nothing */
|
|
return( 1 ) ;
|
|
|
|
return( 0 ) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* get_element()
|
|
*
|
|
* Create a new instance of Element
|
|
*
|
|
****************************************************************************/
|
|
|
|
Element *get_element(long process_id)
|
|
{
|
|
Element *p ;
|
|
|
|
/* Lock the free list */
|
|
LOCK(global->free_element_lock);
|
|
|
|
/* Test pointer */
|
|
if( global->free_element == 0 )
|
|
{
|
|
printf( "Fatal: Ran out of element buffer\n" ) ;
|
|
UNLOCK(global->free_element_lock);
|
|
exit( 1 ) ;
|
|
}
|
|
|
|
/* Get an element data structure */
|
|
p = global->free_element ;
|
|
global->free_element = p->center ;
|
|
global->n_free_elements-- ;
|
|
|
|
/* Unlock the list */
|
|
UNLOCK(global->free_element_lock);
|
|
|
|
/* Clear pointers just in case.. */
|
|
p->parent = 0 ;
|
|
p->center = 0 ;
|
|
p->top = 0 ;
|
|
p->right = 0 ;
|
|
p->left = 0 ;
|
|
p->interactions = 0 ;
|
|
p->n_interactions = 0 ;
|
|
p->vis_undef_inter = 0 ;
|
|
p->n_vis_undef_inter = 0 ;
|
|
|
|
return( p ) ;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* leaf_element()
|
|
*
|
|
* Returns TRUE(1) if this element is a leaf.
|
|
*
|
|
* For strong and processor memory consistency models, this routine is not
|
|
* necessary. For weak and release consistency models, elem->center must be
|
|
* tested within the Lock.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long leaf_element(Element *elem, long process_id)
|
|
{
|
|
long leaf ;
|
|
|
|
LOCK(elem->elem_lock->lock);
|
|
leaf = _LEAF_ELEMENT(elem) ;
|
|
UNLOCK(elem->elem_lock->lock);
|
|
|
|
return( leaf ) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* init_elemlist()
|
|
*
|
|
* Initialize Element free list
|
|
*
|
|
****************************************************************************/
|
|
|
|
void init_elemlist(long process_id)
|
|
{
|
|
long i ;
|
|
|
|
/* Initialize Element free list */
|
|
for( i = 0 ; i < MAX_ELEMENTS-1 ; i++ )
|
|
{
|
|
global->element_buf[i].center = &global->element_buf[i+1] ;
|
|
/* Initialize lock variable */
|
|
global->element_buf[i].elem_lock
|
|
= get_sharedlock( SHARED_LOCK_SEG1, process_id ) ;
|
|
}
|
|
global->element_buf[ MAX_ELEMENTS-1 ].center = 0 ;
|
|
global->element_buf[ MAX_ELEMENTS-1 ].elem_lock
|
|
= get_sharedlock( SHARED_LOCK_SEG1, process_id ) ;
|
|
|
|
global->free_element = global->element_buf ;
|
|
global->n_free_elements = MAX_ELEMENTS ;
|
|
LOCKINIT(global->free_element_lock);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* print_element()
|
|
*
|
|
* Print contents of an element.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void print_element(Element *elem, long process_id)
|
|
{
|
|
printf( "Element (%ld)\n", (long)elem ) ;
|
|
|
|
print_point( &elem->ev1->p ) ;
|
|
print_point( &elem->ev2->p ) ;
|
|
print_point( &elem->ev3->p ) ;
|
|
|
|
printf( "Radiosity:" ) ; print_rgb( &elem->rad ) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
****************************************************************************
|
|
*
|
|
* Methods for Interaction object
|
|
*
|
|
****************************************************************************
|
|
****************************************************************************/
|
|
/***************************************************************************
|
|
*
|
|
* foreach_interaction_in_element()
|
|
*
|
|
* General purpose driver. For each interaction of the element, apply
|
|
* specified function. The function is passed a pointer to the interaction.
|
|
* Traversal is linear.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void foreach_interaction_in_element(Element *elem, void (*func)(), long arg1, long process_id)
|
|
{
|
|
Interaction *inter ;
|
|
|
|
if( elem == 0 )
|
|
return ;
|
|
|
|
for( inter = elem->interactions ; inter ; inter = inter->next )
|
|
func( elem, inter, arg1, process_id ) ;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* compute_interaction()
|
|
* compute_formfactor()
|
|
*
|
|
* compute_interaction() computes all the interaction parameters and fills
|
|
* in the entries of Interaction data structure.
|
|
* compute_formfactor() computes the formfactor only.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void compute_formfactor(Element *e_src, Element *e_dst, Interaction *inter, long process_id)
|
|
{
|
|
float ff_c, ff_1, ff_2, ff_3 ;
|
|
float ff_c1, ff_c2, ff_c3, ff_avg ;
|
|
Vertex pc_src, pc_dst ;
|
|
Vertex pc1_src, pc2_src, pc3_src ;
|
|
float ff_min, ff_max, ff_err ;
|
|
|
|
/* Estimate FF using disk approximation */
|
|
/* (1) Compute FF(diff-disc) from the center of src to the destination */
|
|
four_center_points( &e_src->ev1->p, &e_src->ev2->p, &e_src->ev3->p,
|
|
&pc_src, &pc1_src, &pc2_src, &pc3_src ) ;
|
|
center_point( &e_dst->ev1->p, &e_dst->ev2->p, &e_dst->ev3->p, &pc_dst ) ;
|
|
ff_c = compute_diff_disc_formfactor( &pc_src, e_src, &pc_dst, e_dst, process_id ) ;
|
|
ff_c1 = compute_diff_disc_formfactor( &pc1_src, e_src, &pc_dst, e_dst, process_id ) ;
|
|
ff_c2 = compute_diff_disc_formfactor( &pc2_src, e_src, &pc_dst, e_dst, process_id ) ;
|
|
ff_c3 = compute_diff_disc_formfactor( &pc3_src, e_src, &pc_dst, e_dst, process_id ) ;
|
|
if( ff_c < 0 ) ff_c = 0 ;
|
|
if( ff_c1 < 0 ) ff_c1 = 0 ;
|
|
if( ff_c2 < 0 ) ff_c2 = 0 ;
|
|
if( ff_c3 < 0 ) ff_c3 = 0 ;
|
|
ff_avg = (ff_c + ff_c1 + ff_c2 + ff_c3) * (float)0.25 ;
|
|
ff_min = ff_max = ff_c ;
|
|
if( ff_min > ff_c1 ) ff_min = ff_c1 ;
|
|
if( ff_min > ff_c2 ) ff_min = ff_c2 ;
|
|
if( ff_min > ff_c3 ) ff_min = ff_c3 ;
|
|
if( ff_max < ff_c1 ) ff_max = ff_c1 ;
|
|
if( ff_max < ff_c2 ) ff_max = ff_c2 ;
|
|
if( ff_max < ff_c3 ) ff_max = ff_c3 ;
|
|
|
|
/* (2) Compute FF(diff-disc) from the 3 vertices of the source */
|
|
ff_1 = compute_diff_disc_formfactor( &e_src->ev1->p, e_src,
|
|
&pc_dst, e_dst, process_id ) ;
|
|
ff_2 = compute_diff_disc_formfactor( &e_src->ev2->p, e_src,
|
|
&pc_dst, e_dst, process_id ) ;
|
|
ff_3 = compute_diff_disc_formfactor( &e_src->ev3->p, e_src,
|
|
&pc_dst, e_dst, process_id ) ;
|
|
|
|
/* (3) Find FF min and max */
|
|
ff_min = ff_max = ff_c ;
|
|
if( ff_min > ff_1 ) ff_min = ff_1 ;
|
|
if( ff_min > ff_2 ) ff_min = ff_2 ;
|
|
if( ff_min > ff_3 ) ff_min = ff_3 ;
|
|
if( ff_max < ff_1 ) ff_max = ff_1 ;
|
|
if( ff_max < ff_2 ) ff_max = ff_2 ;
|
|
if( ff_max < ff_3 ) ff_max = ff_3 ;
|
|
|
|
/* (4) Clip FF(diff-disc) if it is negative */
|
|
if( ff_avg < 0 )
|
|
ff_avg = 0 ;
|
|
inter->formfactor_out = ff_avg ;
|
|
|
|
/* (5) Then find maximum difference from the FF at the center */
|
|
ff_err = (ff_max - ff_avg) ;
|
|
if( ff_err < (ff_avg - ff_min) )
|
|
ff_err = ff_avg - ff_min ;
|
|
inter->formfactor_err = ff_err ;
|
|
|
|
/* (6) Correct visibility if partially visible */
|
|
if( (ff_avg < 0) && (inter->visibility == 0) )
|
|
/* All ray missed the visible portion of the elements.
|
|
Set visibility to a non-zero value manually */
|
|
/** inter->visibility = FF_VISIBILITY_ERROR **/ ;
|
|
|
|
/* (7) Fill destination */
|
|
inter->destination = e_dst ;
|
|
}
|
|
|
|
|
|
static float _diff_disc_formfactor(Vertex *p, Element *e_src, Vertex *p_disc, float area, Vertex *normal, long process_id)
|
|
{
|
|
Vertex vec_sd ;
|
|
float dist_sq ;
|
|
float fnorm ;
|
|
float cos_s, cos_d, angle_factor ;
|
|
|
|
vec_sd.x = p_disc->x - p->x ;
|
|
vec_sd.y = p_disc->y - p->y ;
|
|
vec_sd.z = p_disc->z - p->z ;
|
|
dist_sq = vec_sd.x*vec_sd.x + vec_sd.y*vec_sd.y + vec_sd.z*vec_sd.z ;
|
|
|
|
fnorm = area / ((float)M_PI * dist_sq + area) ;
|
|
|
|
/* (2) Now, consider angle to the other patch from the normal. */
|
|
normalize_vector( &vec_sd, &vec_sd ) ;
|
|
cos_s = inner_product( &vec_sd, &e_src->patch->plane_equ.n ) ;
|
|
cos_d = -inner_product( &vec_sd, normal ) ;
|
|
angle_factor = cos_s * cos_d ;
|
|
|
|
/* Return the form factor */
|
|
return( fnorm * angle_factor ) ;
|
|
}
|
|
|
|
|
|
static float compute_diff_disc_formfactor(Vertex *p, Element *e_src, Vertex *p_disc, Element *e_dst, long process_id)
|
|
{
|
|
Vertex p_c, p_c1, p_c2, p_c3 ;
|
|
float quarter_area ;
|
|
float ff_c, ff_c1, ff_c2, ff_c3 ;
|
|
|
|
four_center_points( &e_dst->ev1->p, &e_dst->ev2->p, &e_dst->ev3->p,
|
|
&p_c, &p_c1, &p_c2, &p_c3 ) ;
|
|
|
|
quarter_area = e_dst->area * (float)0.25 ;
|
|
|
|
ff_c = _diff_disc_formfactor( p, e_src, &p_c, quarter_area,
|
|
&e_dst->patch->plane_equ.n, process_id ) ;
|
|
ff_c1= _diff_disc_formfactor( p, e_src, &p_c1, quarter_area,
|
|
&e_dst->patch->plane_equ.n, process_id ) ;
|
|
ff_c2= _diff_disc_formfactor( p, e_src, &p_c2, quarter_area,
|
|
&e_dst->patch->plane_equ.n, process_id ) ;
|
|
ff_c3= _diff_disc_formfactor( p, e_src, &p_c3, quarter_area,
|
|
&e_dst->patch->plane_equ.n, process_id ) ;
|
|
|
|
if( ff_c < 0 ) ff_c = 0 ;
|
|
if( ff_c1 < 0 ) ff_c1 = 0 ;
|
|
if( ff_c2 < 0 ) ff_c2 = 0 ;
|
|
if( ff_c3 < 0 ) ff_c3 = 0 ;
|
|
|
|
return( ff_c + ff_c1 + ff_c2 + ff_c3 ) ;
|
|
}
|
|
|
|
|
|
void compute_interaction(Element *e_src, Element *e_dst, Interaction *inter, long subdiv, long process_id)
|
|
{
|
|
/* (1) Check visibility. */
|
|
if( NO_VISIBILITY_NECESSARY(subdiv) )
|
|
inter->visibility = 1.0 ;
|
|
else
|
|
inter->visibility = VISIBILITY_UNDEF ;
|
|
|
|
|
|
/* (2) Compute formfactor */
|
|
compute_formfactor( e_src, e_dst, inter, process_id ) ;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* insert_interaction()
|
|
* delete_interaction()
|
|
* insert_vis_undef_interaction()
|
|
* delete_vis_undef_interaction()
|
|
*
|
|
* Insert/Delete interaction from the interaction list.
|
|
*
|
|
****************************************************************************/
|
|
|
|
|
|
void insert_interaction(Element *elem, Interaction *inter, long process_id)
|
|
{
|
|
/* Link from patch 1 to patch 2 */
|
|
LOCK(elem->elem_lock->lock);
|
|
inter->next = elem->interactions ;
|
|
elem->interactions = inter ;
|
|
elem->n_interactions++ ;
|
|
UNLOCK(elem->elem_lock->lock);
|
|
}
|
|
|
|
|
|
|
|
void delete_interaction(Element *elem, Interaction *prev, Interaction *inter, long process_id)
|
|
{
|
|
/* Remove from the list */
|
|
LOCK(elem->elem_lock->lock);
|
|
if( prev == 0 )
|
|
elem->interactions = inter->next ;
|
|
else
|
|
prev->next = inter->next ;
|
|
elem->n_interactions-- ;
|
|
UNLOCK(elem->elem_lock->lock);
|
|
|
|
/* Return to the free list */
|
|
free_interaction( inter, process_id ) ;
|
|
}
|
|
|
|
|
|
|
|
void insert_vis_undef_interaction(Element *elem, Interaction *inter, long process_id)
|
|
{
|
|
/* Link from patch 1 to patch 2 */
|
|
LOCK(elem->elem_lock->lock);
|
|
inter->next = elem->vis_undef_inter ;
|
|
elem->vis_undef_inter = inter ;
|
|
elem->n_vis_undef_inter++ ;
|
|
UNLOCK(elem->elem_lock->lock);
|
|
}
|
|
|
|
void delete_vis_undef_interaction(Element *elem, Interaction *prev, Interaction *inter, long process_id)
|
|
{
|
|
/* Remove from the list */
|
|
LOCK(elem->elem_lock->lock);
|
|
if( prev == 0 )
|
|
elem->vis_undef_inter = inter->next ;
|
|
else
|
|
prev->next = inter->next ;
|
|
elem->n_vis_undef_inter-- ;
|
|
UNLOCK(elem->elem_lock->lock);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* get_interaction()
|
|
* free_interaction()
|
|
*
|
|
* Create/delete an instance of an interaction.
|
|
*
|
|
****************************************************************************/
|
|
|
|
Interaction *get_interaction(long process_id)
|
|
{
|
|
Interaction *p ;
|
|
|
|
/* Lock the free list */
|
|
LOCK(global->free_interaction_lock);
|
|
|
|
/* Test pointer */
|
|
if( global->free_interaction == 0 )
|
|
{
|
|
printf( "Fatal: Ran out of interaction buffer\n" ) ;
|
|
UNLOCK(global->free_interaction_lock);
|
|
exit( 1 ) ;
|
|
}
|
|
|
|
/* Get an element data structure */
|
|
p = global->free_interaction ;
|
|
global->free_interaction = p->next ;
|
|
global->n_free_interactions-- ;
|
|
|
|
/* Unlock the list */
|
|
UNLOCK(global->free_interaction_lock);
|
|
|
|
/* Clear pointers just in case.. */
|
|
p->next = 0 ;
|
|
p->destination = 0 ;
|
|
|
|
|
|
return( p ) ;
|
|
}
|
|
|
|
|
|
|
|
void free_interaction(Interaction *interaction, long process_id)
|
|
{
|
|
/* Lock the free list */
|
|
LOCK(global->free_interaction_lock);
|
|
|
|
/* Get a task data structure */
|
|
interaction->next = global->free_interaction ;
|
|
global->free_interaction = interaction ;
|
|
global->n_free_interactions++ ;
|
|
|
|
/* Unlock the list */
|
|
UNLOCK(global->free_interaction_lock);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* init_interactionlist()
|
|
*
|
|
* Initialize Interaction free list
|
|
*
|
|
****************************************************************************/
|
|
|
|
void init_interactionlist(long process_id)
|
|
{
|
|
long i ;
|
|
|
|
/* Initialize Interaction free list */
|
|
for( i = 0 ; i < MAX_INTERACTIONS-1 ; i++ )
|
|
global->interaction_buf[i].next = &global->interaction_buf[i+1] ;
|
|
global->interaction_buf[ MAX_INTERACTIONS-1 ].next = 0 ;
|
|
global->free_interaction = global->interaction_buf ;
|
|
global->n_free_interactions = MAX_INTERACTIONS ;
|
|
LOCKINIT(global->free_interaction_lock);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* print_interaction()
|
|
*
|
|
* Print interaction data structure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void print_interaction(Interaction *inter, long process_id)
|
|
{
|
|
|
|
printf( "Interaction(0x%ld)\n", (long)inter ) ;
|
|
printf( " Dest: Elem (0x%ld) of patch %ld\n",
|
|
(long)inter->destination, inter->destination->patch->seq_no ) ;
|
|
printf( " Fout: %f Vis: %f\n",
|
|
inter->formfactor_out,
|
|
inter->visibility ) ;
|
|
printf( " Next: 0x%p\n", inter->next ) ;
|
|
}
|