| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867 |
- /*****************************************************************************
- * bbox.c
- *
- * This module implements the bounding box calculations.
- * This file was written by Alexander Enzmann. He wrote the code for
- * POV-Ray's bounding boxes and generously provided us these enhancements.
- * The box intersection code was further hacked by Eric Haines to speed it up.
- *
- * Just so everyone knows where this came from, the code is VERY heavily
- * based on the slab code from Mark VandeWettering's MTV raytracer.
- * POV-Ray is just joining the crowd of admirers of Mark's contribution to
- * the public domain. [ARE]
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996,1999 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file.
- * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by email to team-coord@povray.org or visit us on the web at
- * http://www.povray.org. The latest version of POV-Ray may be found at this site.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
- #include "bbox.h"
- #include "matrices.h"
- #include "objects.h"
- #include "povray.h"
- #include "render.h"
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
- #define BUNCHING_FACTOR 4
- /* Initial number of entries in a priority queue. */
- #define INITIAL_PRIORITY_QUEUE_SIZE 256
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
- static BBOX_TREE *create_bbox_node (int size);
- static int find_axis (BBOX_TREE **Finite, long first, long last);
- static void calc_bbox (BBOX *BBox, BBOX_TREE **Finite, long first, long last);
- static void build_area_table (BBOX_TREE **Finite, long a, long b, DBL *areas);
- static int sort_and_split (BBOX_TREE **Root, BBOX_TREE **Finite, long *nFinite, long first, long last);
- static void priority_queue_insert (PRIORITY_QUEUE *Queue, DBL Depth, BBOX_TREE *Node);
- static int CDECL compboxes (CONST void *in_a, CONST void *in_b);
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
- /* Current axis to sort along. */
- static int Axis = 0;
- /* Number of finite elements. */
- static long maxfinitecount = 0;
- /* Priority queue used for frame level bouning box hierarchy. */
- static PRIORITY_QUEUE *Frame_Queue;
- /* Top node of bounding hierarchy. */
- BBOX_TREE *Root_Object;
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Initialize_BBox_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Initialize bbox specific variables.
- *
- * CHANGES
- *
- * Jul 1995 : Creation.
- *
- ******************************************************************************/
- void Initialize_BBox_Code()
- {
- Frame_Queue = Create_Priority_Queue(INITIAL_PRIORITY_QUEUE_SIZE);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Deinitialize_BBox_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Deinitialize bbox specific variables.
- *
- * CHANGES
- *
- * Jul 1995 : Creation.
- *
- ******************************************************************************/
- void Deinitialize_BBox_Code()
- {
- if (Frame_Queue != NULL)
- {
- Destroy_Priority_Queue(Frame_Queue);
- }
- Frame_Queue = NULL;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Priority_Queue
- *
- * INPUT
- *
- * QSize - initial size of priority queue
- *
- * OUTPUT
- *
- * RETURNS
- *
- * PRIORITY_QUEUE * - priority queue
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a priority queue.
- *
- * CHANGES
- *
- * Feb 1995 : Creation.
- *
- ******************************************************************************/
- PRIORITY_QUEUE *Create_Priority_Queue(unsigned QSize)
- {
- PRIORITY_QUEUE *New;
- New = (PRIORITY_QUEUE *)POV_MALLOC(sizeof(PRIORITY_QUEUE), "priority queue");
- New->Queue = (QELEM *)POV_MALLOC(QSize*sizeof(QELEM), "priority queue");
- New->QSize = 0;
- New->Max_QSize = QSize;
- return (New);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Priority_Queue
- *
- * INPUT
- *
- * Queue - Priority queue
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy a priority queue.
- *
- * CHANGES
- *
- * Feb 1995 : Creation.
- *
- ******************************************************************************/
- void Destroy_Priority_Queue(PRIORITY_QUEUE *Queue)
- {
- if (Queue != NULL)
- {
- POV_FREE(Queue->Queue);
- POV_FREE(Queue);
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_BBox_Tree
- *
- * INPUT
- *
- * Node - Node to destroy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Recursively destroy a bounding box tree.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void Destroy_BBox_Tree(BBOX_TREE *Node)
- {
- short i;
- if (Node != NULL)
- {
- if (Node->Entries > 0)
- {
- for (i = 0; i < Node->Entries; i++)
- {
- Destroy_BBox_Tree(Node->Node[i]);
- }
- POV_FREE(Node->Node);
- Node->Entries = 0;
- Node->Node = NULL;
- }
- POV_FREE(Node);
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Recompute_BBox
- *
- * INPUT
- *
- * trans - Transformation
- *
- * OUTPUT
- *
- * bbox - Bounding box
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Recalculate a bounding box after a transformation.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void Recompute_BBox(BBOX *bbox, TRANSFORM *trans)
- {
- int i;
- VECTOR lower_left, lengths, corner;
- VECTOR mins, maxs;
- if (trans == NULL)
- {
- return;
- }
- Assign_BBox_Vect(lower_left, bbox->Lower_Left);
- Assign_BBox_Vect(lengths, bbox->Lengths);
- Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
- for (i = 1; i <= 8; i++)
- {
- Assign_Vector(corner, lower_left);
- corner[X] += ((i & 1) ? lengths[X] : 0.0);
- corner[Y] += ((i & 2) ? lengths[Y] : 0.0);
- corner[Z] += ((i & 4) ? lengths[Z] : 0.0);
- MTransPoint(corner, corner, trans);
- if (corner[X] < mins[X]) { mins[X] = corner[X]; }
- if (corner[X] > maxs[X]) { maxs[X] = corner[X]; }
- if (corner[Y] < mins[Y]) { mins[Y] = corner[Y]; }
- if (corner[Y] > maxs[Y]) { maxs[Y] = corner[Y]; }
- if (corner[Z] < mins[Z]) { mins[Z] = corner[Z]; }
- if (corner[Z] > maxs[Z]) { maxs[Z] = corner[Z]; }
- }
- /* Clip bounding box at the largest allowed bounding box. */
- if (mins[X] < -BOUND_HUGE / 2) { mins[X] = -BOUND_HUGE / 2; }
- if (mins[Y] < -BOUND_HUGE / 2) { mins[Y] = -BOUND_HUGE / 2; }
- if (mins[Z] < -BOUND_HUGE / 2) { mins[Z] = -BOUND_HUGE / 2; }
- if (maxs[X] > BOUND_HUGE / 2) { maxs[X] = BOUND_HUGE / 2; }
- if (maxs[Y] > BOUND_HUGE / 2) { maxs[Y] = BOUND_HUGE / 2; }
- if (maxs[Z] > BOUND_HUGE / 2) { maxs[Z] = BOUND_HUGE / 2; }
- Make_BBox_from_min_max(*bbox, mins, maxs);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Recompute_Inverse_BBox
- *
- * INPUT
- *
- * trans - Transformation
- *
- * OUTPUT
- *
- * bbox - Bounding box
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Recalculate a bounding box after a transformation.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void Recompute_Inverse_BBox(BBOX *bbox, TRANSFORM *trans)
- {
- int i;
- VECTOR lower_left, lengths, corner;
- VECTOR mins, maxs;
- if (trans == NULL)
- {
- return;
- }
- Assign_BBox_Vect(lower_left, bbox->Lower_Left);
- Assign_BBox_Vect(lengths, bbox->Lengths);
- Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
- for (i = 1; i <= 8; i++)
- {
- Assign_Vector(corner, lower_left);
- corner[X] += ((i & 1) ? lengths[X] : 0.0);
- corner[Y] += ((i & 2) ? lengths[Y] : 0.0);
- corner[Z] += ((i & 4) ? lengths[Z] : 0.0);
- MInvTransPoint(corner, corner, trans);
- if (corner[X] < mins[X]) { mins[X] = corner[X]; }
- if (corner[X] > maxs[X]) { maxs[X] = corner[X]; }
- if (corner[Y] < mins[Y]) { mins[Y] = corner[Y]; }
- if (corner[Y] > maxs[Y]) { maxs[Y] = corner[Y]; }
- if (corner[Z] < mins[Z]) { mins[Z] = corner[Z]; }
- if (corner[Z] > maxs[Z]) { maxs[Z] = corner[Z]; }
- }
- /* Clip bounding box at the largest allowed bounding box. */
- if (mins[X] < -BOUND_HUGE / 2) { mins[X] = -BOUND_HUGE / 2; }
- if (mins[Y] < -BOUND_HUGE / 2) { mins[Y] = -BOUND_HUGE / 2; }
- if (mins[Z] < -BOUND_HUGE / 2) { mins[Z] = -BOUND_HUGE / 2; }
- if (maxs[X] > BOUND_HUGE / 2) { maxs[X] = BOUND_HUGE / 2; }
- if (maxs[Y] > BOUND_HUGE / 2) { maxs[Y] = BOUND_HUGE / 2; }
- if (maxs[Z] > BOUND_HUGE / 2) { maxs[Z] = BOUND_HUGE / 2; }
- Make_BBox_from_min_max(*bbox, mins, maxs);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Build_BBox_Tree
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a bounding box hierarchy from a given list of finite and
- * infinite elements. Each element consists of
- *
- * - an infinite flag
- * - a bounding box enclosing the element
- * - a pointer to the structure representing the element (e.g an object)
- *
- * CHANGES
- *
- * Feb 1995 : Creation. (Extracted from Build_Bounding_Slabs)
- * Sep 1995 : Changed to allow use of memcpy if memmove isn't available. [AED]
- * Jul 1996 : Changed to use POV_MEMMOVE, which can be memmove or pov_memmove
- *
- ******************************************************************************/
- void Build_BBox_Tree(BBOX_TREE **Root, long nFinite, BBOX_TREE **Finite, long nInfinite, BBOX_TREE **Infinite)
- {
- short i;
- long low, high;
- BBOX_TREE *cd, *root;
- /*
- * This is a resonable guess at the number of finites needed.
- * This array will be reallocated as needed if it isn't.
- */
- maxfinitecount = 2 * nFinite;
- /*
- * Now do a sort on the objects, with the end result being
- * a tree of objects sorted along the x, y, and z axes.
- */
- if (nFinite > 0)
- {
- low = 0;
- high = nFinite;
- while (sort_and_split(Root, Finite, &nFinite, low, high) == 0)
- {
- low = high;
- high = nFinite;
- }
- /* Move infinite objects in the first leaf of Root. */
- if (nInfinite > 0)
- {
- root = (BBOX_TREE *)(*Root);
- root->Node = (BBOX_TREE **)POV_REALLOC(root->Node, (root->Entries + 1) * sizeof(BBOX_TREE *), "composite");
- POV_MEMMOVE(&(root->Node[1]), &(root->Node[0]), root->Entries * sizeof(BBOX_TREE *));
- root->Entries++;
- cd = create_bbox_node(nInfinite);
- for (i = 0; i < nInfinite; i++)
- {
- cd->Node[i] = Infinite[i];
- }
- calc_bbox(&(cd->BBox), Infinite, 0, nInfinite);
- root->Node[0] = (BBOX_TREE *)cd;
- calc_bbox(&(root->BBox), root->Node, 0, root->Entries);
- /* Root and first node are infinite. */
- root->Infinite = TRUE;
- root->Node[0]->Infinite = TRUE;
- }
- }
- else
- {
- /*
- * There are no finite objects and no Root was created.
- * Create it now and put all infinite objects into it.
- */
- if (nInfinite > 0)
- {
- cd = create_bbox_node(nInfinite);
- for (i = 0; i < nInfinite; i++)
- {
- cd->Node[i] = Infinite[i];
- }
- calc_bbox(&(cd->BBox), Infinite, 0, nInfinite);
- *Root = (BBOX_TREE *)cd;
- (*Root)->Infinite = TRUE;
- }
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Build_Bounding_Slabs
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Create the bounding box hierarchy for all objects in the scene.
- *
- * CHANGES
- *
- * Sep 1994 : Added allocation of priority queue. [DB]
- *
- * Sep 1994 : Added code to put all infinite objects in the first node
- * of the root. Thus the hierarchy won't be messed up. [DB]
- *
- * Sep 1994 : Fixed nIfinite=0 bug. [DB]
- *
- * Feb 1995 : Moved code to actually build the hierarchy. [DB]
- *
- ******************************************************************************/
- void Build_Bounding_Slabs(BBOX_TREE **Root)
- {
- long i, nFinite, nInfinite, iFinite, iInfinite;
- BBOX_TREE **Finite, **Infinite;
- OBJECT *Object, *Temp;
- /* Count frame level and infinite objects. */
- Object = Frame.Objects;
- nFinite = nInfinite = 0;
- while (Object != NULL)
- {
- if (Object->Type & LIGHT_SOURCE_OBJECT)
- {
- Temp = ((LIGHT_SOURCE *)Object)->Children;
- }
- else
- {
- Temp = Object;
- }
- if (Temp != NULL)
- {
- if (Test_Flag(Temp, INFINITE_FLAG))
- {
- nInfinite++;
- }
- else
- {
- nFinite++;
- }
- }
- Object = Object->Sibling;
- }
- /* We want to know how many objects there are. */
- Render_Info("\nScene contains %ld frame level objects; %ld infinite.\n",
- nFinite + nInfinite, nInfinite);
- /* If bounding boxes aren't used we can return. */
- if (!opts.Use_Slabs || !(nFinite + nInfinite >= opts.BBox_Threshold))
- {
- opts.Use_Slabs = FALSE;
- return;
- }
- opts.Use_Slabs = TRUE;
- /*
- * This is a resonable guess at the number of finites needed.
- * This array will be reallocated as needed if it isn't.
- */
- maxfinitecount = 2 * nFinite;
- /*
- * Now allocate an array to hold references to these finites and
- * any new composite objects we may generate.
- */
- Finite = Infinite = NULL;
- if (nFinite > 0)
- {
- Finite = (BBOX_TREE **)POV_MALLOC(maxfinitecount*sizeof(BBOX_TREE *), "bounding boxes");
- }
- /* Create array to hold pointers to infinite objects. */
- if (nInfinite > 0)
- {
- Infinite = (BBOX_TREE **)POV_MALLOC(nInfinite*sizeof(BBOX_TREE *), "bounding boxes");
- }
- /* Init lists. */
- for (i = 0; i < nFinite; i++)
- {
- Finite[i] = create_bbox_node(0);
- }
- for (i = 0; i < nInfinite; i++)
- {
- Infinite[i] = create_bbox_node(0);
- }
- /* Set up finite and infinite object lists. */
- iFinite = iInfinite = 0;
- for (Object = Frame.Objects; Object != NULL; Object = Object->Sibling)
- {
- if (Object->Type & LIGHT_SOURCE_OBJECT)
- {
- Temp = ((LIGHT_SOURCE *)Object)->Children;
- }
- else
- {
- Temp = Object;
- }
- if (Temp != NULL)
- {
- /* Add object to the appropriate list. */
- if (Test_Flag(Temp, INFINITE_FLAG))
- {
- Infinite[iInfinite]->Infinite = TRUE;
- Infinite[iInfinite]->BBox = Temp->BBox;
- Infinite[iInfinite]->Node = (BBOX_TREE **)Temp;
- iInfinite++;
- }
- else
- {
- Finite[iFinite]->BBox = Temp->BBox;
- Finite[iFinite]->Node = (BBOX_TREE **)Temp;
- iFinite++;
- }
- }
- }
- /*
- * Now build the bounding box tree.
- */
- Build_BBox_Tree(Root, nFinite, Finite, nInfinite, Infinite);
- /* Get rid of the Finite and Infinite arrays and just use Root. */
- if (Finite != NULL)
- {
- POV_FREE(Finite);
- }
- if (Infinite != NULL)
- {
- POV_FREE(Infinite);
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Bounding_Slabs
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Destroy the bounding box hierarchy and the priority queue.
- *
- * CHANGES
- *
- * Sep 1994 : Added freeing of priority queue. [DB]
- *
- ******************************************************************************/
- void Destroy_Bounding_Slabs()
- {
- if (Root_Object != NULL)
- {
- Destroy_BBox_Tree(Root_Object);
- Root_Object = NULL;
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Intersect_BBox_Tree
- *
- * INPUT
- *
- * Root - Root node of the bbox tree
- * Ray - Current ray
- *
- * OUTPUT
- *
- * Best_Intersection - Nearest intersection found
- * Best_Object - Nearest object found
- *
- * RETURNS
- *
- * int - TRUE if an intersection was found
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Intersect a ray with a bounding box tree.
- *
- * CHANGES
- *
- * Sep 1994 : Moved priority queue allocation/freeing out of here. [DB]
- *
- ******************************************************************************/
- int Intersect_BBox_Tree(BBOX_TREE *Root, RAY *Ray, INTERSECTION *Best_Intersection, OBJECT **Best_Object)
- {
- int i, found;
- DBL Depth;
- BBOX_TREE *Node;
- RAYINFO rayinfo;
- INTERSECTION New_Intersection;
- /* Create the direction vectors for this ray. */
- Create_Rayinfo(Ray, &rayinfo);
- /* Start with an empty priority queue. */
- found = FALSE;
- Frame_Queue->QSize = 0;
- #ifdef BBOX_EXTRA_STATS
- Increase_Counter(stats[totalQueueResets]);
- #endif
- /* Check top node. */
- Check_And_Enqueue(Frame_Queue, Root, &Root->BBox, &rayinfo);
- /* Check elements in the priority queue. */
- while (Frame_Queue->QSize)
- {
- Priority_Queue_Delete(Frame_Queue, &Depth, &Node);
- /*
- * If current intersection is larger than the best intersection found
- * so far our task is finished, because all other bounding boxes in
- * the priority queue are further away.
- */
- if (Depth > Best_Intersection->Depth)
- {
- break;
- }
- /* Check current node. */
- if (Node->Entries)
- {
- /* This is a node containing leaves to be checked. */
- for (i = 0; i < Node->Entries; i++)
- {
- Check_And_Enqueue(Frame_Queue, Node->Node[i], &Node->Node[i]->BBox, &rayinfo);
- }
- }
- else
- {
- /* This is a leaf so test contained object. */
- if (Intersection(&New_Intersection, (OBJECT *)Node->Node, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
- *Best_Object = (OBJECT *)Node->Node;
- found = TRUE;
- }
- }
- }
- }
- return (found);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * priority_queue_insert
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Insert an element in the priority queue.
- *
- * CHANGES
- *
- * Sep 1994 : Added code for resizing the priority queue. [DB]
- *
- ******************************************************************************/
- static void priority_queue_insert(PRIORITY_QUEUE *Queue, DBL Depth, BBOX_TREE *Node)
- {
- unsigned size;
- int i;
- QELEM tmp, *List;
- #ifdef BBOX_EXTRA_STATS
- Increase_Counter(stats[totalQueues]);
- #endif
- Queue->QSize++;
- size = Queue->QSize;
- /* Reallocate priority queue if it's too small. */
- if (size >= Queue->Max_QSize)
- {
- if (size >= INT_MAX/2)
- {
- Error("Priority queue overflow.\n");
- }
- #ifdef BBOX_EXTRA_STATS
- Increase_Counter(stats[totalQueueResizes]);
- #endif
- Queue->Max_QSize *= 2;
- Queue->Queue = (QELEM *)POV_REALLOC(Queue->Queue, Queue->Max_QSize*sizeof(QELEM), "priority queue");
- }
- List = Queue->Queue;
-
- List[size].Depth = Depth;
- List[size].Node = Node;
-
- i = size;
-
- while (i > 1 && List[i].Depth < List[i / 2].Depth)
- {
- tmp = List[i];
- List[i] = List[i / 2];
- List[i / 2] = tmp;
- i = i / 2;
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Priority_Queue_Delete
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Get an element from the priority queue.
- *
- * NOTE: This element will always be the one closest to the ray origin.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void Priority_Queue_Delete(PRIORITY_QUEUE *Queue, DBL *Depth, BBOX_TREE **Node)
- {
- QELEM tmp, *List;
- int i, j;
- unsigned size;
- if (Queue->QSize == 0)
- {
- Error("priority queue is empty.\n");
- }
- List = Queue->Queue;
- *Depth = List[1].Depth;
- *Node = List[1].Node;
- List[1] = List[Queue->QSize];
- Queue->QSize--;
- size = Queue->QSize;
- i = 1;
- while (2 * i <= (int)size)
- {
- if (2 * i == (int)size)
- {
- j = 2 * i;
- }
- else
- {
- if (List[2*i].Depth < List[2*i+1].Depth)
- {
- j = 2 * i;
- }
- else
- {
- j = 2 * i + 1;
- }
- }
- if (List[i].Depth > List[j].Depth)
- {
- tmp = List[i];
- List[i] = List[j];
- List[j] = tmp;
- i = j;
- }
- else
- {
- break;
- }
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Check_And_Enqueue
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * If a given ray intersect the object's bounding box then add it
- * to the priority queue.
- *
- * CHANGES
- *
- * Sep 1994 : Pass bounding box seperately.
- * This is needed for the vista/light buffer. [DB]
- *
- * Sep 1994 : Added code to insert infinte objects without testing. [DB]
- *
- ******************************************************************************/
- void Check_And_Enqueue(PRIORITY_QUEUE *Queue, BBOX_TREE *Node, BBOX *BBox, RAYINFO *rayinfo)
- {
- DBL tmin, tmax;
- DBL dmin, dmax;
- if (Node->Infinite)
- {
- /* Set intersection depth to -Max_Distance. */
- dmin = -Max_Distance;
- }
- else
- {
- Increase_Counter(stats[nChecked]);
- if (rayinfo->nonzero[X])
- {
- if (rayinfo->positive[X])
- {
- dmin = (BBox->Lower_Left[X] - rayinfo->slab_num[X]) * rayinfo->slab_den[X];
- dmax = dmin + (BBox->Lengths[X] * rayinfo->slab_den[X]);
- if (dmax < EPSILON) return;
- }
- else
- {
- dmax = (BBox->Lower_Left[X] - rayinfo->slab_num[X]) * rayinfo->slab_den[X];
- if (dmax < EPSILON) return;
- dmin = dmax + (BBox->Lengths[X] * rayinfo->slab_den[X]);
- }
- if (dmin > dmax) return;
- }
- else
- {
- if ((rayinfo->slab_num[X] < BBox->Lower_Left[X]) ||
- (rayinfo->slab_num[X] > BBox->Lengths[X] + BBox->Lower_Left[X]))
- {
- return;
- }
- dmin = -BOUND_HUGE;
- dmax = BOUND_HUGE;
- }
- if (rayinfo->nonzero[Y])
- {
- if (rayinfo->positive[Y])
- {
- tmin = (BBox->Lower_Left[Y] - rayinfo->slab_num[Y]) * rayinfo->slab_den[Y];
- tmax = tmin + (BBox->Lengths[Y] * rayinfo->slab_den[Y]);
- }
- else
- {
- tmax = (BBox->Lower_Left[Y] - rayinfo->slab_num[Y]) * rayinfo->slab_den[Y];
- tmin = tmax + (BBox->Lengths[Y] * rayinfo->slab_den[Y]);
- }
- /*
- * Unwrap the logic - do the dmin and dmax checks only when tmin and
- * tmax actually affect anything, also try to escape ASAP. Better
- * yet, fold the logic below into the two branches above so as to
- * compute only what is needed.
- */
- /*
- * You might even try tmax < EPSILON first (instead of second) for an
- * early quick out.
- */
- if (tmax < dmax)
- {
- if (tmax < EPSILON) return;
- /* check bbox only if tmax changes dmax */
- if (tmin > dmin)
- {
- if (tmin > tmax) return;
- /* do this last in case it's not needed! */
- dmin = tmin;
- }
- else
- {
- if (dmin > tmax) return;
- }
- /* do this last in case it's not needed! */
- dmax = tmax;
- }
- else
- {
- if (tmin > dmin)
- {
- if (tmin > dmax) return;
-
- /* do this last in case it's not needed! */
-
- dmin = tmin;
- }
- /* else nothing needs to happen, since dmin and dmax did not change! */
- }
- }
- else
- {
- if ((rayinfo->slab_num[Y] < BBox->Lower_Left[Y]) ||
- (rayinfo->slab_num[Y] > BBox->Lengths[Y] + BBox->Lower_Left[Y]))
- {
- return;
- }
- }
-
- if (rayinfo->nonzero[Z])
- {
- if (rayinfo->positive[Z])
- {
- tmin = (BBox->Lower_Left[Z] - rayinfo->slab_num[Z]) * rayinfo->slab_den[Z];
-
- tmax = tmin + (BBox->Lengths[Z] * rayinfo->slab_den[Z]);
- }
- else
- {
- tmax = (BBox->Lower_Left[Z] - rayinfo->slab_num[Z]) * rayinfo->slab_den[Z];
- tmin = tmax + (BBox->Lengths[Z] * rayinfo->slab_den[Z]);
- }
- if (tmax < dmax)
- {
- if (tmax < EPSILON) return;
- /* check bbox only if tmax changes dmax */
- if (tmin > dmin)
- {
- if (tmin > tmax) return;
- /* do this last in case it's not needed! */
- dmin = tmin;
- }
- else
- {
- if (dmin > tmax) return;
- }
- }
- else
- {
- if (tmin > dmin)
- {
- if (tmin > dmax) return;
- /* do this last in case it's not needed! */
- dmin = tmin;
- }
- /* else nothing needs to happen, since dmin and dmax did not change! */
- }
- }
- else
- {
- if ((rayinfo->slab_num[Z] < BBox->Lower_Left[Z]) ||
- (rayinfo->slab_num[Z] > BBox->Lengths[Z] + BBox->Lower_Left[Z]))
- {
- return;
- }
- }
- Increase_Counter(stats[nEnqueued]);
- }
- priority_queue_insert(Queue, dmin, Node);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Rayinfo
- *
- * INPUT
- *
- * Ray - Current ray
- * rayinfo - Rayinfo structure
- *
- * OUTPUT
- *
- * rayinfo
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate the rayinfo structure for a given ray. It's need for
- * intersection the ray with bounding boxes.
- *
- * CHANGES
- *
- * May 1994 : Creation. (Extracted from Intersect_BBox_Tree)
- *
- ******************************************************************************/
- void Create_Rayinfo(RAY *Ray, RAYINFO *rayinfo)
- {
- DBL t;
- /* Create the direction vectors for this ray */
- Assign_Vector(rayinfo->slab_num, Ray->Initial);
- if ((rayinfo->nonzero[X] = ((t = Ray->Direction[X]) != 0.0)) != 0)
- {
- rayinfo->slab_den[X] = 1.0 / t;
- rayinfo->positive[X] = (Ray->Direction[X] > 0.0);
- }
- if ((rayinfo->nonzero[Y] = ((t = Ray->Direction[Y]) != 0.0)) != 0)
- {
- rayinfo->slab_den[Y] = 1.0 / t;
- rayinfo->positive[Y] = (Ray->Direction[Y] > 0.0);
- }
- if ((rayinfo->nonzero[Z] = ((t = Ray->Direction[Z]) != 0.0)) != 0)
- {
- rayinfo->slab_den[Z] = 1.0 / t;
- rayinfo->positive[Z] = (Ray->Direction[Z] > 0.0);
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * create_bbox_node
- *
- * INPUT
- *
- * size - Number of subnodes
- *
- * OUTPUT
- *
- * RETURNS
- *
- * BBOX_TREE * - New node
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static BBOX_TREE *create_bbox_node(int size)
- {
- BBOX_TREE *New;
- New = (BBOX_TREE *)POV_MALLOC(sizeof(BBOX_TREE), "bounding box node");
- New->Infinite = FALSE;
- New->Entries = size;
- Make_BBox(New->BBox, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
- if (size)
- {
- New->Node = (BBOX_TREE **)POV_MALLOC(size*sizeof(BBOX_TREE *), "bounding box node");
- }
- else
- {
- New->Node = NULL;
- }
- return (New);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * compboxes
- *
- * INPUT
- *
- * in_a, in_b - Elements to compare
- *
- * OUTPUT
- *
- * RETURNS
- *
- * int - result of comparison
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Sep 1994 : Removed test for infinite objects because it's obsolete. [DB]
- *
- ******************************************************************************/
- static int CDECL compboxes(CONST void *in_a, CONST void *in_b)
- {
- BBOX *a, *b;
- BBOX_VAL am, bm;
- a = &((*(BBOX_TREE **)in_a)->BBox);
- b = &((*(BBOX_TREE **)in_b)->BBox);
- am = 2.0 * a->Lower_Left[Axis] + a->Lengths[Axis];
- bm = 2.0 * b->Lower_Left[Axis] + b->Lengths[Axis];
- if (am < bm)
- {
- return (-1);
- }
- else
- {
- if (am == bm)
- {
- return (0);
- }
- else
- {
- return (1);
- }
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * find_axis
- *
- * INPUT
- *
- * Finite - Array of finite elements
- * first, last - Position of elements
- *
- * OUTPUT
- *
- * RETURNS
- *
- * int - Axis to sort along
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Find the axis along which the elements will be sorted.
- *
- * CHANGES
- *
- * Sep 1994 : Initialize local variable which. [DB]
- *
- ******************************************************************************/
- static int find_axis(BBOX_TREE **Finite, long first, long last)
- {
- int which = X;
- long i;
- DBL e, d = -BOUND_HUGE;
- VECTOR mins, maxs;
- BBOX *bbox;
- Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
- for (i = first; i < last; i++)
- {
- bbox = &(Finite[i]->BBox);
- if (bbox->Lower_Left[X] < mins[X])
- {
- mins[X] = bbox->Lower_Left[X];
- }
- if (bbox->Lower_Left[X] + bbox->Lengths[X] > maxs[X])
- {
- maxs[X] = bbox->Lower_Left[X];
- }
- if (bbox->Lower_Left[Y] < mins[Y])
- {
- mins[Y] = bbox->Lower_Left[Y];
- }
- if (bbox->Lower_Left[Y] + bbox->Lengths[Y] > maxs[Y])
- {
- maxs[Y] = bbox->Lower_Left[Y];
- }
- if (bbox->Lower_Left[Z] < mins[Z])
- {
- mins[Z] = bbox->Lower_Left[Z];
- }
- if (bbox->Lower_Left[Z] + bbox->Lengths[Z] > maxs[Z])
- {
- maxs[Z] = bbox->Lower_Left[Z];
- }
- }
- e = maxs[X] - mins[X];
- if (e > d)
- {
- d = e; which = X;
- }
- e = maxs[Y] - mins[Y];
- if (e > d)
- {
- d = e; which = Y;
- }
- e = maxs[Z] - mins[Z];
- if (e > d)
- {
- which = Z;
- }
- return (which);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * calc_bbox
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Calculate the bounding box containing Finite[first] through Finite[last-1].
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void calc_bbox(BBOX *BBox, BBOX_TREE **Finite, long first, long last)
- {
- long i;
- DBL tmin, tmax;
- VECTOR bmin, bmax;
- BBOX *bbox;
- COOPERATE_1
- Make_Vector(bmin, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(bmax, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
- for (i = first; i < last; i++)
- {
- bbox = &(Finite[i]->BBox);
- tmin = bbox->Lower_Left[X];
- tmax = tmin + bbox->Lengths[X];
- if (tmin < bmin[X]) { bmin[X] = tmin; }
- if (tmax > bmax[X]) { bmax[X] = tmax; }
- tmin = bbox->Lower_Left[Y];
- tmax = tmin + bbox->Lengths[Y];
- if (tmin < bmin[Y]) { bmin[Y] = tmin; }
- if (tmax > bmax[Y]) { bmax[Y] = tmax; }
- tmin = bbox->Lower_Left[Z];
- tmax = tmin + bbox->Lengths[Z];
- if (tmin < bmin[Z]) { bmin[Z] = tmin; }
- if (tmax > bmax[Z]) { bmax[Z] = tmax; }
- }
- Make_BBox_from_min_max(*BBox, bmin, bmax);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * build_area_table
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Generates a table of bound box surface areas.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void build_area_table(BBOX_TREE **Finite, long a, long b, DBL *areas)
- {
- long i, imin, dir;
- DBL tmin, tmax;
- VECTOR bmin, bmax, len;
- BBOX *bbox;
- if (a < b)
- {
- imin = a; dir = 1;
- }
- else
- {
- imin = b; dir = -1;
- }
- Make_Vector(bmin, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(bmax, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
- for (i = a; i != (b + dir); i += dir)
- {
- bbox = &(Finite[i]->BBox);
- tmin = bbox->Lower_Left[X];
- tmax = tmin + bbox->Lengths[X];
- if (tmin < bmin[X]) { bmin[X] = tmin; }
- if (tmax > bmax[X]) { bmax[X] = tmax; }
- tmin = bbox->Lower_Left[Y];
- tmax = tmin + bbox->Lengths[Y];
- if (tmin < bmin[Y]) { bmin[Y] = tmin; }
- if (tmax > bmax[Y]) { bmax[Y] = tmax; }
- tmin = bbox->Lower_Left[Z];
- tmax = tmin + bbox->Lengths[Z];
- if (tmin < bmin[Z]) { bmin[Z] = tmin; }
- if (tmax > bmax[Z]) { bmax[Z] = tmax; }
- VSub(len, bmax, bmin);
- areas[i - imin] = len[X] * (len[Y] + len[Z]) + len[Y] * len[Z];
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * sort_and_split
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static int sort_and_split(BBOX_TREE **Root, BBOX_TREE **Finite, long *nFinite, long first, long last)
- {
- BBOX_TREE *cd;
- long size, i, best_loc;
- DBL *area_left, *area_right;
- DBL best_index, new_index;
- Axis = find_axis(Finite, first, last);
- size = last - first;
- if (size <= 0)
- {
- return (1);
- }
- /*
- * Actually, we could do this faster in several ways. We could use a
- * logn algorithm to find the median along the given axis, and then a
- * linear algorithm to partition along the axis. Oh well.
- */
- QSORT((void *)(&Finite[first]), (unsigned long)size, sizeof(BBOX_TREE *), compboxes);
- /*
- * area_left[] and area_right[] hold the surface areas of the bounding
- * boxes to the left and right of any given point. E.g. area_left[i] holds
- * the surface area of the bounding box containing Finite 0 through i and
- * area_right[i] holds the surface area of the box containing Finite
- * i through size-1.
- */
- area_left = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes");
- area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes");
- /* Precalculate the areas for speed. */
- build_area_table(Finite, first, last - 1, area_left);
- build_area_table(Finite, last - 1, first, area_right);
- best_index = area_right[0] * (size - 3.0);
- best_loc = -1;
- /*
- * Find the most effective point to split. The best location will be
- * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
- * are the number of objects in the two groups and A1 and A2 are the
- * surface areas of the bounding boxes of the two groups.
- */
- for (i = 0; i < size - 1; i++)
- {
- new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1];
- if (new_index < best_index)
- {
- best_index = new_index;
- best_loc = i + first;
- }
- }
- POV_FREE(area_left);
- POV_FREE(area_right);
- /*
- * Stop splitting if the BUNCHING_FACTOR is reached or
- * if splitting stops being effective.
- */
- if ((size <= BUNCHING_FACTOR) || (best_loc < 0))
- {
- cd = create_bbox_node(size);
-
- for (i = 0; i < size; i++)
- {
- cd->Node[i] = Finite[first+i];
- }
- calc_bbox(&(cd->BBox), Finite, first, last);
- *Root = (BBOX_TREE *)cd;
- if (*nFinite > maxfinitecount)
- {
- /* Prim array overrun, increase array by 50%. */
- maxfinitecount = 1.5 * maxfinitecount;
- /* For debugging only. */
- Debug_Info("Reallocing Finite to %d\n", maxfinitecount);
- Finite = (BBOX_TREE **)POV_REALLOC(Finite, maxfinitecount * sizeof(BBOX_TREE *), "bounding boxes");
- }
- Finite[*nFinite] = cd;
- (*nFinite)++;
- return (1);
- }
- else
- {
- sort_and_split(Root, Finite, nFinite, first, best_loc + 1);
- sort_and_split(Root, Finite, nFinite, best_loc + 1, last);
- return (0);
- }
- }
|