Simple test for asyncio.library.
[AROS-Contrib.git] / gfx / povray / bbox.c
blob1dc18ccaf69535bb5631626d52a7f7a221cad12c
1 /*****************************************************************************
2 * bbox.c
4 * This module implements the bounding box calculations.
5 * This file was written by Alexander Enzmann. He wrote the code for
6 * POV-Ray's bounding boxes and generously provided us these enhancements.
7 * The box intersection code was further hacked by Eric Haines to speed it up.
9 * Just so everyone knows where this came from, the code is VERY heavily
10 * based on the slab code from Mark VandeWettering's MTV raytracer.
11 * POV-Ray is just joining the crowd of admirers of Mark's contribution to
12 * the public domain. [ARE]
14 * from Persistence of Vision(tm) Ray Tracer
15 * Copyright 1996,1999 Persistence of Vision Team
16 *---------------------------------------------------------------------------
17 * NOTICE: This source code file is provided so that users may experiment
18 * with enhancements to POV-Ray and to port the software to platforms other
19 * than those supported by the POV-Ray Team. There are strict rules under
20 * which you are permitted to use this file. The rules are in the file
21 * named POVLEGAL.DOC which should be distributed with this file.
22 * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
23 * Team Coordinator by email to team-coord@povray.org or visit us on the web at
24 * http://www.povray.org. The latest version of POV-Ray may be found at this site.
26 * This program is based on the popular DKB raytracer version 2.12.
27 * DKBTrace was originally written by David K. Buck.
28 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
30 *****************************************************************************/
32 #include "frame.h"
33 #include "vector.h"
34 #include "povproto.h"
35 #include "bbox.h"
36 #include "matrices.h"
37 #include "objects.h"
38 #include "povray.h"
39 #include "render.h"
43 /*****************************************************************************
44 * Local preprocessor defines
45 ******************************************************************************/
47 #define BUNCHING_FACTOR 4
49 /* Initial number of entries in a priority queue. */
51 #define INITIAL_PRIORITY_QUEUE_SIZE 256
55 /*****************************************************************************
56 * Local typedefs
57 ******************************************************************************/
61 /*****************************************************************************
62 * Static functions
63 ******************************************************************************/
65 static BBOX_TREE *create_bbox_node (int size);
67 static int find_axis (BBOX_TREE **Finite, long first, long last);
68 static void calc_bbox (BBOX *BBox, BBOX_TREE **Finite, long first, long last);
69 static void build_area_table (BBOX_TREE **Finite, long a, long b, DBL *areas);
70 static int sort_and_split (BBOX_TREE **Root, BBOX_TREE **Finite, long *nFinite, long first, long last);
72 static void priority_queue_insert (PRIORITY_QUEUE *Queue, DBL Depth, BBOX_TREE *Node);
74 static int CDECL compboxes (CONST void *in_a, CONST void *in_b);
77 /*****************************************************************************
78 * Local variables
79 ******************************************************************************/
81 /* Current axis to sort along. */
83 static int Axis = 0;
85 /* Number of finite elements. */
87 static long maxfinitecount = 0;
89 /* Priority queue used for frame level bouning box hierarchy. */
91 static PRIORITY_QUEUE *Frame_Queue;
93 /* Top node of bounding hierarchy. */
95 BBOX_TREE *Root_Object;
99 /*****************************************************************************
101 * FUNCTION
103 * Initialize_BBox_Code
105 * INPUT
107 * OUTPUT
109 * RETURNS
111 * AUTHOR
113 * Dieter Bayer
115 * DESCRIPTION
117 * Initialize bbox specific variables.
119 * CHANGES
121 * Jul 1995 : Creation.
123 ******************************************************************************/
125 void Initialize_BBox_Code()
127 Frame_Queue = Create_Priority_Queue(INITIAL_PRIORITY_QUEUE_SIZE);
132 /*****************************************************************************
134 * FUNCTION
136 * Deinitialize_BBox_Code
138 * INPUT
140 * OUTPUT
142 * RETURNS
144 * AUTHOR
146 * Dieter Bayer
148 * DESCRIPTION
150 * Deinitialize bbox specific variables.
152 * CHANGES
154 * Jul 1995 : Creation.
156 ******************************************************************************/
158 void Deinitialize_BBox_Code()
160 if (Frame_Queue != NULL)
162 Destroy_Priority_Queue(Frame_Queue);
165 Frame_Queue = NULL;
170 /*****************************************************************************
172 * FUNCTION
174 * Create_Priority_Queue
176 * INPUT
178 * QSize - initial size of priority queue
180 * OUTPUT
182 * RETURNS
184 * PRIORITY_QUEUE * - priority queue
186 * AUTHOR
188 * Dieter Bayer
190 * DESCRIPTION
192 * Create a priority queue.
194 * CHANGES
196 * Feb 1995 : Creation.
198 ******************************************************************************/
200 PRIORITY_QUEUE *Create_Priority_Queue(unsigned QSize)
202 PRIORITY_QUEUE *New;
204 New = (PRIORITY_QUEUE *)POV_MALLOC(sizeof(PRIORITY_QUEUE), "priority queue");
206 New->Queue = (QELEM *)POV_MALLOC(QSize*sizeof(QELEM), "priority queue");
208 New->QSize = 0;
210 New->Max_QSize = QSize;
212 return (New);
217 /*****************************************************************************
219 * FUNCTION
221 * Destroy_Priority_Queue
223 * INPUT
225 * Queue - Priority queue
227 * OUTPUT
229 * RETURNS
231 * AUTHOR
233 * Dieter Bayer
235 * DESCRIPTION
237 * Destroy a priority queue.
239 * CHANGES
241 * Feb 1995 : Creation.
243 ******************************************************************************/
245 void Destroy_Priority_Queue(PRIORITY_QUEUE *Queue)
247 if (Queue != NULL)
249 POV_FREE(Queue->Queue);
251 POV_FREE(Queue);
257 /*****************************************************************************
259 * FUNCTION
261 * Destroy_BBox_Tree
263 * INPUT
265 * Node - Node to destroy
267 * OUTPUT
269 * RETURNS
271 * AUTHOR
273 * Dieter Bayer
275 * DESCRIPTION
277 * Recursively destroy a bounding box tree.
279 * CHANGES
283 ******************************************************************************/
285 void Destroy_BBox_Tree(BBOX_TREE *Node)
287 short i;
289 if (Node != NULL)
291 if (Node->Entries > 0)
293 for (i = 0; i < Node->Entries; i++)
295 Destroy_BBox_Tree(Node->Node[i]);
298 POV_FREE(Node->Node);
300 Node->Entries = 0;
302 Node->Node = NULL;
305 POV_FREE(Node);
311 /*****************************************************************************
313 * FUNCTION
315 * Recompute_BBox
317 * INPUT
319 * trans - Transformation
321 * OUTPUT
323 * bbox - Bounding box
325 * RETURNS
327 * AUTHOR
329 * Alexander Enzmann
331 * DESCRIPTION
333 * Recalculate a bounding box after a transformation.
335 * CHANGES
339 ******************************************************************************/
341 void Recompute_BBox(BBOX *bbox, TRANSFORM *trans)
343 int i;
344 VECTOR lower_left, lengths, corner;
345 VECTOR mins, maxs;
347 if (trans == NULL)
349 return;
352 Assign_BBox_Vect(lower_left, bbox->Lower_Left);
353 Assign_BBox_Vect(lengths, bbox->Lengths);
355 Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
356 Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
358 for (i = 1; i <= 8; i++)
360 Assign_Vector(corner, lower_left);
362 corner[X] += ((i & 1) ? lengths[X] : 0.0);
363 corner[Y] += ((i & 2) ? lengths[Y] : 0.0);
364 corner[Z] += ((i & 4) ? lengths[Z] : 0.0);
366 MTransPoint(corner, corner, trans);
368 if (corner[X] < mins[X]) { mins[X] = corner[X]; }
369 if (corner[X] > maxs[X]) { maxs[X] = corner[X]; }
370 if (corner[Y] < mins[Y]) { mins[Y] = corner[Y]; }
371 if (corner[Y] > maxs[Y]) { maxs[Y] = corner[Y]; }
372 if (corner[Z] < mins[Z]) { mins[Z] = corner[Z]; }
373 if (corner[Z] > maxs[Z]) { maxs[Z] = corner[Z]; }
376 /* Clip bounding box at the largest allowed bounding box. */
378 if (mins[X] < -BOUND_HUGE / 2) { mins[X] = -BOUND_HUGE / 2; }
379 if (mins[Y] < -BOUND_HUGE / 2) { mins[Y] = -BOUND_HUGE / 2; }
380 if (mins[Z] < -BOUND_HUGE / 2) { mins[Z] = -BOUND_HUGE / 2; }
381 if (maxs[X] > BOUND_HUGE / 2) { maxs[X] = BOUND_HUGE / 2; }
382 if (maxs[Y] > BOUND_HUGE / 2) { maxs[Y] = BOUND_HUGE / 2; }
383 if (maxs[Z] > BOUND_HUGE / 2) { maxs[Z] = BOUND_HUGE / 2; }
385 Make_BBox_from_min_max(*bbox, mins, maxs);
390 /*****************************************************************************
392 * FUNCTION
394 * Recompute_Inverse_BBox
396 * INPUT
398 * trans - Transformation
400 * OUTPUT
402 * bbox - Bounding box
404 * RETURNS
406 * AUTHOR
408 * Alexander Enzmann
410 * DESCRIPTION
412 * Recalculate a bounding box after a transformation.
414 * CHANGES
418 ******************************************************************************/
420 void Recompute_Inverse_BBox(BBOX *bbox, TRANSFORM *trans)
422 int i;
423 VECTOR lower_left, lengths, corner;
424 VECTOR mins, maxs;
426 if (trans == NULL)
428 return;
431 Assign_BBox_Vect(lower_left, bbox->Lower_Left);
432 Assign_BBox_Vect(lengths, bbox->Lengths);
434 Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
435 Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
437 for (i = 1; i <= 8; i++)
439 Assign_Vector(corner, lower_left);
441 corner[X] += ((i & 1) ? lengths[X] : 0.0);
442 corner[Y] += ((i & 2) ? lengths[Y] : 0.0);
443 corner[Z] += ((i & 4) ? lengths[Z] : 0.0);
445 MInvTransPoint(corner, corner, trans);
447 if (corner[X] < mins[X]) { mins[X] = corner[X]; }
448 if (corner[X] > maxs[X]) { maxs[X] = corner[X]; }
449 if (corner[Y] < mins[Y]) { mins[Y] = corner[Y]; }
450 if (corner[Y] > maxs[Y]) { maxs[Y] = corner[Y]; }
451 if (corner[Z] < mins[Z]) { mins[Z] = corner[Z]; }
452 if (corner[Z] > maxs[Z]) { maxs[Z] = corner[Z]; }
455 /* Clip bounding box at the largest allowed bounding box. */
457 if (mins[X] < -BOUND_HUGE / 2) { mins[X] = -BOUND_HUGE / 2; }
458 if (mins[Y] < -BOUND_HUGE / 2) { mins[Y] = -BOUND_HUGE / 2; }
459 if (mins[Z] < -BOUND_HUGE / 2) { mins[Z] = -BOUND_HUGE / 2; }
460 if (maxs[X] > BOUND_HUGE / 2) { maxs[X] = BOUND_HUGE / 2; }
461 if (maxs[Y] > BOUND_HUGE / 2) { maxs[Y] = BOUND_HUGE / 2; }
462 if (maxs[Z] > BOUND_HUGE / 2) { maxs[Z] = BOUND_HUGE / 2; }
464 Make_BBox_from_min_max(*bbox, mins, maxs);
469 /*****************************************************************************
471 * FUNCTION
473 * Build_BBox_Tree
475 * INPUT
477 * OUTPUT
479 * RETURNS
481 * AUTHOR
483 * Dieter Bayer
485 * DESCRIPTION
487 * Create a bounding box hierarchy from a given list of finite and
488 * infinite elements. Each element consists of
490 * - an infinite flag
491 * - a bounding box enclosing the element
492 * - a pointer to the structure representing the element (e.g an object)
494 * CHANGES
496 * Feb 1995 : Creation. (Extracted from Build_Bounding_Slabs)
497 * Sep 1995 : Changed to allow use of memcpy if memmove isn't available. [AED]
498 * Jul 1996 : Changed to use POV_MEMMOVE, which can be memmove or pov_memmove
500 ******************************************************************************/
502 void Build_BBox_Tree(BBOX_TREE **Root, long nFinite, BBOX_TREE **Finite, long nInfinite, BBOX_TREE **Infinite)
504 short i;
505 long low, high;
506 BBOX_TREE *cd, *root;
509 * This is a resonable guess at the number of finites needed.
510 * This array will be reallocated as needed if it isn't.
513 maxfinitecount = 2 * nFinite;
516 * Now do a sort on the objects, with the end result being
517 * a tree of objects sorted along the x, y, and z axes.
520 if (nFinite > 0)
522 low = 0;
523 high = nFinite;
525 while (sort_and_split(Root, Finite, &nFinite, low, high) == 0)
527 low = high;
528 high = nFinite;
531 /* Move infinite objects in the first leaf of Root. */
533 if (nInfinite > 0)
535 root = (BBOX_TREE *)(*Root);
537 root->Node = (BBOX_TREE **)POV_REALLOC(root->Node, (root->Entries + 1) * sizeof(BBOX_TREE *), "composite");
539 POV_MEMMOVE(&(root->Node[1]), &(root->Node[0]), root->Entries * sizeof(BBOX_TREE *));
541 root->Entries++;
543 cd = create_bbox_node(nInfinite);
545 for (i = 0; i < nInfinite; i++)
547 cd->Node[i] = Infinite[i];
550 calc_bbox(&(cd->BBox), Infinite, 0, nInfinite);
552 root->Node[0] = (BBOX_TREE *)cd;
554 calc_bbox(&(root->BBox), root->Node, 0, root->Entries);
556 /* Root and first node are infinite. */
558 root->Infinite = TRUE;
560 root->Node[0]->Infinite = TRUE;
563 else
566 * There are no finite objects and no Root was created.
567 * Create it now and put all infinite objects into it.
570 if (nInfinite > 0)
572 cd = create_bbox_node(nInfinite);
574 for (i = 0; i < nInfinite; i++)
576 cd->Node[i] = Infinite[i];
579 calc_bbox(&(cd->BBox), Infinite, 0, nInfinite);
581 *Root = (BBOX_TREE *)cd;
583 (*Root)->Infinite = TRUE;
590 /*****************************************************************************
592 * FUNCTION
594 * Build_Bounding_Slabs
596 * INPUT
598 * OUTPUT
600 * RETURNS
602 * AUTHOR
604 * Alexander Enzmann
606 * DESCRIPTION
608 * Create the bounding box hierarchy for all objects in the scene.
610 * CHANGES
612 * Sep 1994 : Added allocation of priority queue. [DB]
614 * Sep 1994 : Added code to put all infinite objects in the first node
615 * of the root. Thus the hierarchy won't be messed up. [DB]
617 * Sep 1994 : Fixed nIfinite=0 bug. [DB]
619 * Feb 1995 : Moved code to actually build the hierarchy. [DB]
621 ******************************************************************************/
623 void Build_Bounding_Slabs(BBOX_TREE **Root)
625 long i, nFinite, nInfinite, iFinite, iInfinite;
626 BBOX_TREE **Finite, **Infinite;
627 OBJECT *Object, *Temp;
629 /* Count frame level and infinite objects. */
631 Object = Frame.Objects;
633 nFinite = nInfinite = 0;
635 while (Object != NULL)
637 if (Object->Type & LIGHT_SOURCE_OBJECT)
639 Temp = ((LIGHT_SOURCE *)Object)->Children;
641 else
643 Temp = Object;
646 if (Temp != NULL)
648 if (Test_Flag(Temp, INFINITE_FLAG))
650 nInfinite++;
652 else
654 nFinite++;
658 Object = Object->Sibling;
661 /* We want to know how many objects there are. */
663 Render_Info("\nScene contains %ld frame level objects; %ld infinite.\n",
664 nFinite + nInfinite, nInfinite);
666 /* If bounding boxes aren't used we can return. */
668 if (!opts.Use_Slabs || !(nFinite + nInfinite >= opts.BBox_Threshold))
670 opts.Use_Slabs = FALSE;
672 return;
675 opts.Use_Slabs = TRUE;
678 * This is a resonable guess at the number of finites needed.
679 * This array will be reallocated as needed if it isn't.
682 maxfinitecount = 2 * nFinite;
685 * Now allocate an array to hold references to these finites and
686 * any new composite objects we may generate.
689 Finite = Infinite = NULL;
691 if (nFinite > 0)
693 Finite = (BBOX_TREE **)POV_MALLOC(maxfinitecount*sizeof(BBOX_TREE *), "bounding boxes");
696 /* Create array to hold pointers to infinite objects. */
698 if (nInfinite > 0)
700 Infinite = (BBOX_TREE **)POV_MALLOC(nInfinite*sizeof(BBOX_TREE *), "bounding boxes");
703 /* Init lists. */
705 for (i = 0; i < nFinite; i++)
707 Finite[i] = create_bbox_node(0);
710 for (i = 0; i < nInfinite; i++)
712 Infinite[i] = create_bbox_node(0);
715 /* Set up finite and infinite object lists. */
717 iFinite = iInfinite = 0;
719 for (Object = Frame.Objects; Object != NULL; Object = Object->Sibling)
721 if (Object->Type & LIGHT_SOURCE_OBJECT)
723 Temp = ((LIGHT_SOURCE *)Object)->Children;
725 else
727 Temp = Object;
730 if (Temp != NULL)
732 /* Add object to the appropriate list. */
734 if (Test_Flag(Temp, INFINITE_FLAG))
736 Infinite[iInfinite]->Infinite = TRUE;
737 Infinite[iInfinite]->BBox = Temp->BBox;
738 Infinite[iInfinite]->Node = (BBOX_TREE **)Temp;
740 iInfinite++;
742 else
744 Finite[iFinite]->BBox = Temp->BBox;
745 Finite[iFinite]->Node = (BBOX_TREE **)Temp;
747 iFinite++;
753 * Now build the bounding box tree.
756 Build_BBox_Tree(Root, nFinite, Finite, nInfinite, Infinite);
758 /* Get rid of the Finite and Infinite arrays and just use Root. */
760 if (Finite != NULL)
762 POV_FREE(Finite);
765 if (Infinite != NULL)
767 POV_FREE(Infinite);
773 /*****************************************************************************
775 * FUNCTION
777 * Destroy_Bounding_Slabs
779 * INPUT
781 * OUTPUT
783 * RETURNS
785 * AUTHOR
787 * Alexander Enzmann
789 * DESCRIPTION
791 * Destroy the bounding box hierarchy and the priority queue.
793 * CHANGES
795 * Sep 1994 : Added freeing of priority queue. [DB]
797 ******************************************************************************/
799 void Destroy_Bounding_Slabs()
801 if (Root_Object != NULL)
803 Destroy_BBox_Tree(Root_Object);
805 Root_Object = NULL;
811 /*****************************************************************************
813 * FUNCTION
815 * Intersect_BBox_Tree
817 * INPUT
819 * Root - Root node of the bbox tree
820 * Ray - Current ray
822 * OUTPUT
824 * Best_Intersection - Nearest intersection found
825 * Best_Object - Nearest object found
827 * RETURNS
829 * int - TRUE if an intersection was found
831 * AUTHOR
833 * Alexander Enzmann
835 * DESCRIPTION
837 * Intersect a ray with a bounding box tree.
839 * CHANGES
841 * Sep 1994 : Moved priority queue allocation/freeing out of here. [DB]
843 ******************************************************************************/
845 int Intersect_BBox_Tree(BBOX_TREE *Root, RAY *Ray, INTERSECTION *Best_Intersection, OBJECT **Best_Object)
847 int i, found;
848 DBL Depth;
849 BBOX_TREE *Node;
850 RAYINFO rayinfo;
851 INTERSECTION New_Intersection;
853 /* Create the direction vectors for this ray. */
855 Create_Rayinfo(Ray, &rayinfo);
857 /* Start with an empty priority queue. */
859 found = FALSE;
861 Frame_Queue->QSize = 0;
863 #ifdef BBOX_EXTRA_STATS
864 Increase_Counter(stats[totalQueueResets]);
865 #endif
867 /* Check top node. */
869 Check_And_Enqueue(Frame_Queue, Root, &Root->BBox, &rayinfo);
871 /* Check elements in the priority queue. */
873 while (Frame_Queue->QSize)
875 Priority_Queue_Delete(Frame_Queue, &Depth, &Node);
878 * If current intersection is larger than the best intersection found
879 * so far our task is finished, because all other bounding boxes in
880 * the priority queue are further away.
883 if (Depth > Best_Intersection->Depth)
885 break;
888 /* Check current node. */
890 if (Node->Entries)
892 /* This is a node containing leaves to be checked. */
894 for (i = 0; i < Node->Entries; i++)
896 Check_And_Enqueue(Frame_Queue, Node->Node[i], &Node->Node[i]->BBox, &rayinfo);
899 else
901 /* This is a leaf so test contained object. */
903 if (Intersection(&New_Intersection, (OBJECT *)Node->Node, Ray))
905 if (New_Intersection.Depth < Best_Intersection->Depth)
907 *Best_Intersection = New_Intersection;
909 *Best_Object = (OBJECT *)Node->Node;
911 found = TRUE;
917 return (found);
922 /*****************************************************************************
924 * FUNCTION
926 * priority_queue_insert
928 * INPUT
930 * OUTPUT
932 * RETURNS
934 * AUTHOR
936 * Alexander Enzmann
938 * DESCRIPTION
940 * Insert an element in the priority queue.
942 * CHANGES
944 * Sep 1994 : Added code for resizing the priority queue. [DB]
946 ******************************************************************************/
948 static void priority_queue_insert(PRIORITY_QUEUE *Queue, DBL Depth, BBOX_TREE *Node)
950 unsigned size;
951 int i;
952 QELEM tmp, *List;
954 #ifdef BBOX_EXTRA_STATS
955 Increase_Counter(stats[totalQueues]);
956 #endif
958 Queue->QSize++;
960 size = Queue->QSize;
962 /* Reallocate priority queue if it's too small. */
964 if (size >= Queue->Max_QSize)
966 if (size >= INT_MAX/2)
968 Error("Priority queue overflow.\n");
971 #ifdef BBOX_EXTRA_STATS
972 Increase_Counter(stats[totalQueueResizes]);
973 #endif
975 Queue->Max_QSize *= 2;
977 Queue->Queue = (QELEM *)POV_REALLOC(Queue->Queue, Queue->Max_QSize*sizeof(QELEM), "priority queue");
980 List = Queue->Queue;
982 List[size].Depth = Depth;
983 List[size].Node = Node;
985 i = size;
987 while (i > 1 && List[i].Depth < List[i / 2].Depth)
989 tmp = List[i];
991 List[i] = List[i / 2];
993 List[i / 2] = tmp;
995 i = i / 2;
1001 /*****************************************************************************
1003 * FUNCTION
1005 * Priority_Queue_Delete
1007 * INPUT
1009 * OUTPUT
1011 * RETURNS
1013 * AUTHOR
1015 * Alexander Enzmann
1017 * DESCRIPTION
1019 * Get an element from the priority queue.
1021 * NOTE: This element will always be the one closest to the ray origin.
1023 * CHANGES
1027 ******************************************************************************/
1029 void Priority_Queue_Delete(PRIORITY_QUEUE *Queue, DBL *Depth, BBOX_TREE **Node)
1031 QELEM tmp, *List;
1032 int i, j;
1033 unsigned size;
1035 if (Queue->QSize == 0)
1037 Error("priority queue is empty.\n");
1040 List = Queue->Queue;
1042 *Depth = List[1].Depth;
1043 *Node = List[1].Node;
1045 List[1] = List[Queue->QSize];
1047 Queue->QSize--;
1049 size = Queue->QSize;
1051 i = 1;
1053 while (2 * i <= (int)size)
1055 if (2 * i == (int)size)
1057 j = 2 * i;
1059 else
1061 if (List[2*i].Depth < List[2*i+1].Depth)
1063 j = 2 * i;
1065 else
1067 j = 2 * i + 1;
1071 if (List[i].Depth > List[j].Depth)
1073 tmp = List[i];
1075 List[i] = List[j];
1077 List[j] = tmp;
1079 i = j;
1081 else
1083 break;
1090 /*****************************************************************************
1092 * FUNCTION
1094 * Check_And_Enqueue
1096 * INPUT
1098 * OUTPUT
1100 * RETURNS
1102 * AUTHOR
1104 * Alexander Enzmann
1106 * DESCRIPTION
1108 * If a given ray intersect the object's bounding box then add it
1109 * to the priority queue.
1111 * CHANGES
1113 * Sep 1994 : Pass bounding box seperately.
1114 * This is needed for the vista/light buffer. [DB]
1116 * Sep 1994 : Added code to insert infinte objects without testing. [DB]
1118 ******************************************************************************/
1120 void Check_And_Enqueue(PRIORITY_QUEUE *Queue, BBOX_TREE *Node, BBOX *BBox, RAYINFO *rayinfo)
1122 DBL tmin, tmax;
1123 DBL dmin, dmax;
1125 if (Node->Infinite)
1127 /* Set intersection depth to -Max_Distance. */
1129 dmin = -Max_Distance;
1131 else
1133 Increase_Counter(stats[nChecked]);
1135 if (rayinfo->nonzero[X])
1137 if (rayinfo->positive[X])
1139 dmin = (BBox->Lower_Left[X] - rayinfo->slab_num[X]) * rayinfo->slab_den[X];
1141 dmax = dmin + (BBox->Lengths[X] * rayinfo->slab_den[X]);
1143 if (dmax < EPSILON) return;
1145 else
1147 dmax = (BBox->Lower_Left[X] - rayinfo->slab_num[X]) * rayinfo->slab_den[X];
1149 if (dmax < EPSILON) return;
1151 dmin = dmax + (BBox->Lengths[X] * rayinfo->slab_den[X]);
1154 if (dmin > dmax) return;
1156 else
1158 if ((rayinfo->slab_num[X] < BBox->Lower_Left[X]) ||
1159 (rayinfo->slab_num[X] > BBox->Lengths[X] + BBox->Lower_Left[X]))
1161 return;
1164 dmin = -BOUND_HUGE;
1165 dmax = BOUND_HUGE;
1168 if (rayinfo->nonzero[Y])
1170 if (rayinfo->positive[Y])
1172 tmin = (BBox->Lower_Left[Y] - rayinfo->slab_num[Y]) * rayinfo->slab_den[Y];
1174 tmax = tmin + (BBox->Lengths[Y] * rayinfo->slab_den[Y]);
1176 else
1178 tmax = (BBox->Lower_Left[Y] - rayinfo->slab_num[Y]) * rayinfo->slab_den[Y];
1180 tmin = tmax + (BBox->Lengths[Y] * rayinfo->slab_den[Y]);
1184 * Unwrap the logic - do the dmin and dmax checks only when tmin and
1185 * tmax actually affect anything, also try to escape ASAP. Better
1186 * yet, fold the logic below into the two branches above so as to
1187 * compute only what is needed.
1191 * You might even try tmax < EPSILON first (instead of second) for an
1192 * early quick out.
1195 if (tmax < dmax)
1197 if (tmax < EPSILON) return;
1199 /* check bbox only if tmax changes dmax */
1201 if (tmin > dmin)
1203 if (tmin > tmax) return;
1205 /* do this last in case it's not needed! */
1207 dmin = tmin;
1209 else
1211 if (dmin > tmax) return;
1214 /* do this last in case it's not needed! */
1216 dmax = tmax;
1218 else
1220 if (tmin > dmin)
1222 if (tmin > dmax) return;
1224 /* do this last in case it's not needed! */
1226 dmin = tmin;
1229 /* else nothing needs to happen, since dmin and dmax did not change! */
1232 else
1234 if ((rayinfo->slab_num[Y] < BBox->Lower_Left[Y]) ||
1235 (rayinfo->slab_num[Y] > BBox->Lengths[Y] + BBox->Lower_Left[Y]))
1237 return;
1241 if (rayinfo->nonzero[Z])
1243 if (rayinfo->positive[Z])
1245 tmin = (BBox->Lower_Left[Z] - rayinfo->slab_num[Z]) * rayinfo->slab_den[Z];
1247 tmax = tmin + (BBox->Lengths[Z] * rayinfo->slab_den[Z]);
1249 else
1251 tmax = (BBox->Lower_Left[Z] - rayinfo->slab_num[Z]) * rayinfo->slab_den[Z];
1253 tmin = tmax + (BBox->Lengths[Z] * rayinfo->slab_den[Z]);
1256 if (tmax < dmax)
1258 if (tmax < EPSILON) return;
1260 /* check bbox only if tmax changes dmax */
1262 if (tmin > dmin)
1264 if (tmin > tmax) return;
1266 /* do this last in case it's not needed! */
1268 dmin = tmin;
1270 else
1272 if (dmin > tmax) return;
1275 else
1277 if (tmin > dmin)
1279 if (tmin > dmax) return;
1281 /* do this last in case it's not needed! */
1283 dmin = tmin;
1286 /* else nothing needs to happen, since dmin and dmax did not change! */
1289 else
1291 if ((rayinfo->slab_num[Z] < BBox->Lower_Left[Z]) ||
1292 (rayinfo->slab_num[Z] > BBox->Lengths[Z] + BBox->Lower_Left[Z]))
1294 return;
1298 Increase_Counter(stats[nEnqueued]);
1301 priority_queue_insert(Queue, dmin, Node);
1306 /*****************************************************************************
1308 * FUNCTION
1310 * Create_Rayinfo
1312 * INPUT
1314 * Ray - Current ray
1315 * rayinfo - Rayinfo structure
1317 * OUTPUT
1319 * rayinfo
1321 * RETURNS
1323 * AUTHOR
1325 * Dieter Bayer
1327 * DESCRIPTION
1329 * Calculate the rayinfo structure for a given ray. It's need for
1330 * intersection the ray with bounding boxes.
1332 * CHANGES
1334 * May 1994 : Creation. (Extracted from Intersect_BBox_Tree)
1336 ******************************************************************************/
1338 void Create_Rayinfo(RAY *Ray, RAYINFO *rayinfo)
1340 DBL t;
1342 /* Create the direction vectors for this ray */
1344 Assign_Vector(rayinfo->slab_num, Ray->Initial);
1346 if ((rayinfo->nonzero[X] = ((t = Ray->Direction[X]) != 0.0)) != 0)
1348 rayinfo->slab_den[X] = 1.0 / t;
1350 rayinfo->positive[X] = (Ray->Direction[X] > 0.0);
1353 if ((rayinfo->nonzero[Y] = ((t = Ray->Direction[Y]) != 0.0)) != 0)
1355 rayinfo->slab_den[Y] = 1.0 / t;
1357 rayinfo->positive[Y] = (Ray->Direction[Y] > 0.0);
1360 if ((rayinfo->nonzero[Z] = ((t = Ray->Direction[Z]) != 0.0)) != 0)
1362 rayinfo->slab_den[Z] = 1.0 / t;
1364 rayinfo->positive[Z] = (Ray->Direction[Z] > 0.0);
1370 /*****************************************************************************
1372 * FUNCTION
1374 * create_bbox_node
1376 * INPUT
1378 * size - Number of subnodes
1380 * OUTPUT
1382 * RETURNS
1384 * BBOX_TREE * - New node
1386 * AUTHOR
1388 * Alexander Enzmann
1390 * DESCRIPTION
1394 * CHANGES
1398 ******************************************************************************/
1400 static BBOX_TREE *create_bbox_node(int size)
1402 BBOX_TREE *New;
1404 New = (BBOX_TREE *)POV_MALLOC(sizeof(BBOX_TREE), "bounding box node");
1406 New->Infinite = FALSE;
1408 New->Entries = size;
1410 Make_BBox(New->BBox, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
1412 if (size)
1414 New->Node = (BBOX_TREE **)POV_MALLOC(size*sizeof(BBOX_TREE *), "bounding box node");
1416 else
1418 New->Node = NULL;
1421 return (New);
1426 /*****************************************************************************
1428 * FUNCTION
1430 * compboxes
1432 * INPUT
1434 * in_a, in_b - Elements to compare
1436 * OUTPUT
1438 * RETURNS
1440 * int - result of comparison
1442 * AUTHOR
1444 * Alexander Enzmann
1446 * DESCRIPTION
1450 * CHANGES
1452 * Sep 1994 : Removed test for infinite objects because it's obsolete. [DB]
1454 ******************************************************************************/
1456 static int CDECL compboxes(CONST void *in_a, CONST void *in_b)
1458 BBOX *a, *b;
1459 BBOX_VAL am, bm;
1461 a = &((*(BBOX_TREE **)in_a)->BBox);
1462 b = &((*(BBOX_TREE **)in_b)->BBox);
1464 am = 2.0 * a->Lower_Left[Axis] + a->Lengths[Axis];
1465 bm = 2.0 * b->Lower_Left[Axis] + b->Lengths[Axis];
1467 if (am < bm)
1469 return (-1);
1471 else
1473 if (am == bm)
1475 return (0);
1477 else
1479 return (1);
1486 /*****************************************************************************
1488 * FUNCTION
1490 * find_axis
1492 * INPUT
1494 * Finite - Array of finite elements
1495 * first, last - Position of elements
1497 * OUTPUT
1499 * RETURNS
1501 * int - Axis to sort along
1503 * AUTHOR
1505 * Alexander Enzmann
1507 * DESCRIPTION
1509 * Find the axis along which the elements will be sorted.
1511 * CHANGES
1513 * Sep 1994 : Initialize local variable which. [DB]
1515 ******************************************************************************/
1517 static int find_axis(BBOX_TREE **Finite, long first, long last)
1519 int which = X;
1520 long i;
1521 DBL e, d = -BOUND_HUGE;
1522 VECTOR mins, maxs;
1523 BBOX *bbox;
1525 Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
1526 Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
1528 for (i = first; i < last; i++)
1530 bbox = &(Finite[i]->BBox);
1532 if (bbox->Lower_Left[X] < mins[X])
1534 mins[X] = bbox->Lower_Left[X];
1537 if (bbox->Lower_Left[X] + bbox->Lengths[X] > maxs[X])
1539 maxs[X] = bbox->Lower_Left[X];
1542 if (bbox->Lower_Left[Y] < mins[Y])
1544 mins[Y] = bbox->Lower_Left[Y];
1547 if (bbox->Lower_Left[Y] + bbox->Lengths[Y] > maxs[Y])
1549 maxs[Y] = bbox->Lower_Left[Y];
1552 if (bbox->Lower_Left[Z] < mins[Z])
1554 mins[Z] = bbox->Lower_Left[Z];
1557 if (bbox->Lower_Left[Z] + bbox->Lengths[Z] > maxs[Z])
1559 maxs[Z] = bbox->Lower_Left[Z];
1563 e = maxs[X] - mins[X];
1565 if (e > d)
1567 d = e; which = X;
1570 e = maxs[Y] - mins[Y];
1572 if (e > d)
1574 d = e; which = Y;
1577 e = maxs[Z] - mins[Z];
1579 if (e > d)
1581 which = Z;
1584 return (which);
1589 /*****************************************************************************
1591 * FUNCTION
1593 * calc_bbox
1595 * INPUT
1597 * OUTPUT
1599 * RETURNS
1601 * AUTHOR
1603 * Alexander Enzmann
1605 * DESCRIPTION
1607 * Calculate the bounding box containing Finite[first] through Finite[last-1].
1609 * CHANGES
1613 ******************************************************************************/
1615 static void calc_bbox(BBOX *BBox, BBOX_TREE **Finite, long first, long last)
1617 long i;
1618 DBL tmin, tmax;
1619 VECTOR bmin, bmax;
1620 BBOX *bbox;
1622 COOPERATE_1
1624 Make_Vector(bmin, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
1625 Make_Vector(bmax, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
1627 for (i = first; i < last; i++)
1629 bbox = &(Finite[i]->BBox);
1631 tmin = bbox->Lower_Left[X];
1632 tmax = tmin + bbox->Lengths[X];
1634 if (tmin < bmin[X]) { bmin[X] = tmin; }
1635 if (tmax > bmax[X]) { bmax[X] = tmax; }
1637 tmin = bbox->Lower_Left[Y];
1638 tmax = tmin + bbox->Lengths[Y];
1640 if (tmin < bmin[Y]) { bmin[Y] = tmin; }
1641 if (tmax > bmax[Y]) { bmax[Y] = tmax; }
1643 tmin = bbox->Lower_Left[Z];
1644 tmax = tmin + bbox->Lengths[Z];
1646 if (tmin < bmin[Z]) { bmin[Z] = tmin; }
1647 if (tmax > bmax[Z]) { bmax[Z] = tmax; }
1650 Make_BBox_from_min_max(*BBox, bmin, bmax);
1655 /*****************************************************************************
1657 * FUNCTION
1659 * build_area_table
1661 * INPUT
1663 * OUTPUT
1665 * RETURNS
1667 * AUTHOR
1669 * Alexander Enzmann
1671 * DESCRIPTION
1673 * Generates a table of bound box surface areas.
1675 * CHANGES
1679 ******************************************************************************/
1681 static void build_area_table(BBOX_TREE **Finite, long a, long b, DBL *areas)
1683 long i, imin, dir;
1684 DBL tmin, tmax;
1685 VECTOR bmin, bmax, len;
1686 BBOX *bbox;
1688 if (a < b)
1690 imin = a; dir = 1;
1692 else
1694 imin = b; dir = -1;
1697 Make_Vector(bmin, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
1698 Make_Vector(bmax, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
1700 for (i = a; i != (b + dir); i += dir)
1702 bbox = &(Finite[i]->BBox);
1704 tmin = bbox->Lower_Left[X];
1705 tmax = tmin + bbox->Lengths[X];
1707 if (tmin < bmin[X]) { bmin[X] = tmin; }
1708 if (tmax > bmax[X]) { bmax[X] = tmax; }
1710 tmin = bbox->Lower_Left[Y];
1711 tmax = tmin + bbox->Lengths[Y];
1713 if (tmin < bmin[Y]) { bmin[Y] = tmin; }
1714 if (tmax > bmax[Y]) { bmax[Y] = tmax; }
1716 tmin = bbox->Lower_Left[Z];
1717 tmax = tmin + bbox->Lengths[Z];
1719 if (tmin < bmin[Z]) { bmin[Z] = tmin; }
1720 if (tmax > bmax[Z]) { bmax[Z] = tmax; }
1722 VSub(len, bmax, bmin);
1724 areas[i - imin] = len[X] * (len[Y] + len[Z]) + len[Y] * len[Z];
1730 /*****************************************************************************
1732 * FUNCTION
1734 * sort_and_split
1736 * INPUT
1738 * OUTPUT
1740 * RETURNS
1742 * AUTHOR
1744 * Alexander Enzmann
1746 * DESCRIPTION
1750 * CHANGES
1754 ******************************************************************************/
1756 static int sort_and_split(BBOX_TREE **Root, BBOX_TREE **Finite, long *nFinite, long first, long last)
1758 BBOX_TREE *cd;
1759 long size, i, best_loc;
1760 DBL *area_left, *area_right;
1761 DBL best_index, new_index;
1763 Axis = find_axis(Finite, first, last);
1765 size = last - first;
1767 if (size <= 0)
1769 return (1);
1773 * Actually, we could do this faster in several ways. We could use a
1774 * logn algorithm to find the median along the given axis, and then a
1775 * linear algorithm to partition along the axis. Oh well.
1778 QSORT((void *)(&Finite[first]), (unsigned long)size, sizeof(BBOX_TREE *), compboxes);
1781 * area_left[] and area_right[] hold the surface areas of the bounding
1782 * boxes to the left and right of any given point. E.g. area_left[i] holds
1783 * the surface area of the bounding box containing Finite 0 through i and
1784 * area_right[i] holds the surface area of the box containing Finite
1785 * i through size-1.
1788 area_left = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes");
1789 area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes");
1791 /* Precalculate the areas for speed. */
1793 build_area_table(Finite, first, last - 1, area_left);
1794 build_area_table(Finite, last - 1, first, area_right);
1796 best_index = area_right[0] * (size - 3.0);
1798 best_loc = -1;
1801 * Find the most effective point to split. The best location will be
1802 * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
1803 * are the number of objects in the two groups and A1 and A2 are the
1804 * surface areas of the bounding boxes of the two groups.
1807 for (i = 0; i < size - 1; i++)
1809 new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1];
1811 if (new_index < best_index)
1813 best_index = new_index;
1814 best_loc = i + first;
1818 POV_FREE(area_left);
1819 POV_FREE(area_right);
1822 * Stop splitting if the BUNCHING_FACTOR is reached or
1823 * if splitting stops being effective.
1826 if ((size <= BUNCHING_FACTOR) || (best_loc < 0))
1828 cd = create_bbox_node(size);
1830 for (i = 0; i < size; i++)
1832 cd->Node[i] = Finite[first+i];
1835 calc_bbox(&(cd->BBox), Finite, first, last);
1837 *Root = (BBOX_TREE *)cd;
1839 if (*nFinite > maxfinitecount)
1841 /* Prim array overrun, increase array by 50%. */
1843 maxfinitecount = 1.5 * maxfinitecount;
1845 /* For debugging only. */
1847 Debug_Info("Reallocing Finite to %d\n", maxfinitecount);
1849 Finite = (BBOX_TREE **)POV_REALLOC(Finite, maxfinitecount * sizeof(BBOX_TREE *), "bounding boxes");
1852 Finite[*nFinite] = cd;
1854 (*nFinite)++;
1856 return (1);
1858 else
1860 sort_and_split(Root, Finite, nFinite, first, best_loc + 1);
1862 sort_and_split(Root, Finite, nFinite, best_loc + 1, last);
1864 return (0);