Attempt to fix nightly build.
[AROS-Contrib.git] / gfx / povray / boxes.c
blob6bb9fcb145bc57326d94c0dc2d71065eca7e8676
1 /****************************************************************************
2 * boxes.c
4 * This module implements the box primitive.
5 * This file was written by Alexander Enzmann. He wrote the code for
6 * boxes and generously provided us these enhancements.
8 * from Persistence of Vision(tm) Ray Tracer
9 * Copyright 1996,1999 Persistence of Vision Team
10 *---------------------------------------------------------------------------
11 * NOTICE: This source code file is provided so that users may experiment
12 * with enhancements to POV-Ray and to port the software to platforms other
13 * than those supported by the POV-Ray Team. There are strict rules under
14 * which you are permitted to use this file. The rules are in the file
15 * named POVLEGAL.DOC which should be distributed with this file.
16 * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
17 * Team Coordinator by email to team-coord@povray.org or visit us on the web at
18 * http://www.povray.org. The latest version of POV-Ray may be found at this site.
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24 *****************************************************************************/
26 #include "frame.h"
27 #include "povray.h"
28 #include "vector.h"
29 #include "povproto.h"
30 #include "bbox.h"
31 #include "boxes.h"
32 #include "matrices.h"
33 #include "objects.h"
37 /*****************************************************************************
38 * Local preprocessor defines
39 ******************************************************************************/
41 /* Minimal intersection depth. */
43 #define DEPTH_TOLERANCE 1.0e-6
45 /* Two values are equal if their difference is small than CLOSE_TOLERANCE. */
47 #define CLOSE_TOLERANCE 1.0e-6
49 /* Side hit. */
51 #define SIDE_X_0 1
52 #define SIDE_X_1 2
53 #define SIDE_Y_0 3
54 #define SIDE_Y_1 4
55 #define SIDE_Z_0 5
56 #define SIDE_Z_1 6
60 /*****************************************************************************
61 * Static functions
62 ******************************************************************************/
63 static int All_Box_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
64 static int Inside_Box (VECTOR point, OBJECT *Object);
65 static void Box_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
66 static void Translate_Box (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
67 static void Rotate_Box (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
68 static void Scale_Box (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
69 static void Transform_Box (OBJECT *Object, TRANSFORM *Trans);
70 static void Invert_Box (OBJECT *Object);
74 /*****************************************************************************
75 * Local variables
76 ******************************************************************************/
78 METHODS Box_Methods =
80 All_Box_Intersections,
81 Inside_Box, Box_Normal,
82 (COPY_METHOD)Copy_Box, Translate_Box, Rotate_Box, Scale_Box, Transform_Box,
83 Invert_Box, Destroy_Box
88 /*****************************************************************************
90 * FUNCTION
92 * All_Box_Intersections
94 * INPUT
96 * OUTPUT
98 * RETURNS
100 * AUTHOR
102 * Alexander Enzmann
104 * DESCRIPTION
108 * CHANGES
112 ******************************************************************************/
114 static int All_Box_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
116 int Intersection_Found;
117 int Side1, Side2;
118 DBL Depth1, Depth2;
119 VECTOR IPoint;
121 Increase_Counter(stats[Ray_Box_Tests]);
123 Intersection_Found = FALSE;
125 if (Intersect_Box(Ray, (BOX *)Object, &Depth1, &Depth2, &Side1, &Side2))
127 if (Depth1 > DEPTH_TOLERANCE)
129 VEvaluateRay(IPoint, Ray->Initial, Depth1, Ray->Direction);
131 if (Point_In_Clip(IPoint, Object->Clip))
133 push_entry_i1(Depth1,IPoint,Object,Side1,Depth_Stack);
135 Intersection_Found = TRUE;
139 VEvaluateRay(IPoint, Ray->Initial, Depth2, Ray->Direction);
141 if (Point_In_Clip(IPoint, Object->Clip))
143 push_entry_i1(Depth2,IPoint,Object,Side2,Depth_Stack);
145 Intersection_Found = TRUE;
149 if (Intersection_Found)
151 Increase_Counter(stats[Ray_Box_Tests_Succeeded]);
154 return (Intersection_Found);
159 /*****************************************************************************
161 * FUNCTION
163 * Intersect_Box
165 * INPUT
167 * OUTPUT
169 * RETURNS
171 * AUTHOR
173 * Alexander Enzmann
175 * DESCRIPTION
179 * CHANGES
181 * Sep 1994 : Added code to decide which side was hit in the case
182 * intersection points are close to each other. This removes
183 * some ugly artefacts one could observe at the corners of
184 * boxes due to the usage of the wrong normal vector. [DB]
186 ******************************************************************************/
188 int Intersect_Box(RAY *Ray, BOX *box, DBL *Depth1, DBL *Depth2, int *Side1, int *Side2)
190 int smin = 0, smax = 0; /* Side hit for min/max intersection. */
191 DBL t, tmin, tmax;
192 VECTOR P, D;
194 /* Transform the point into the boxes space */
196 if (box->Trans != NULL)
198 MInvTransPoint(P, Ray->Initial, box->Trans);
199 MInvTransDirection(D, Ray->Direction, box->Trans);
201 else
203 Assign_Vector(P, Ray->Initial);
204 Assign_Vector(D, Ray->Direction);
207 tmin = 0.0;
208 tmax = BOUND_HUGE;
211 * Sides first.
214 if (D[X] < -EPSILON)
216 t = (box->bounds[0][X] - P[X]) / D[X];
218 if (t < tmin) return(FALSE);
220 if (t <= tmax)
222 smax = SIDE_X_0;
223 tmax = t;
226 t = (box->bounds[1][X] - P[X]) / D[X];
228 if (t >= tmin)
230 if (t > tmax) return(FALSE);
232 smin = SIDE_X_1;
233 tmin = t;
236 else
238 if (D[X] > EPSILON)
240 t = (box->bounds[1][X] - P[X]) / D[X];
242 if (t < tmin) return(FALSE);
244 if (t <= tmax)
246 smax = SIDE_X_1;
247 tmax = t;
250 t = (box->bounds[0][X] - P[X]) / D[X];
252 if (t >= tmin)
254 if (t > tmax) return(FALSE);
256 smin = SIDE_X_0;
257 tmin = t;
260 else
262 if ((P[X] < box->bounds[0][X]) || (P[X] > box->bounds[1][X]))
264 return(FALSE);
270 * Check Top/Bottom.
273 if (D[Y] < -EPSILON)
275 t = (box->bounds[0][Y] - P[Y]) / D[Y];
277 if (t < tmin) return(FALSE);
279 if (t <= tmax - CLOSE_TOLERANCE)
281 smax = SIDE_Y_0;
282 tmax = t;
284 else
287 * If intersection points are close to each other find out
288 * which side to use, i.e. is most probably hit. [DB 9/94]
291 if (t <= tmax + CLOSE_TOLERANCE)
293 if (-D[Y] > fabs(D[X])) smax = SIDE_Y_0;
297 t = (box->bounds[1][Y] - P[Y]) / D[Y];
299 if (t >= tmin + CLOSE_TOLERANCE)
301 if (t > tmax) return(FALSE);
303 smin = SIDE_Y_1;
304 tmin = t;
306 else
309 * If intersection points are close to each other find out
310 * which side to use, i.e. is most probably hit. [DB 9/94]
313 if (t >= tmin - CLOSE_TOLERANCE)
315 if (-D[Y] > fabs(D[X])) smin = SIDE_Y_1;
319 else
321 if (D[Y] > EPSILON)
323 t = (box->bounds[1][Y] - P[Y]) / D[Y];
325 if (t < tmin) return(FALSE);
327 if (t <= tmax - CLOSE_TOLERANCE)
329 smax = SIDE_Y_1;
330 tmax = t;
332 else
335 * If intersection points are close to each other find out
336 * which side to use, i.e. is most probably hit. [DB 9/94]
339 if (t <= tmax + CLOSE_TOLERANCE)
341 if (D[Y] > fabs(D[X])) smax = SIDE_Y_1;
345 t = (box->bounds[0][Y] - P[Y]) / D[Y];
347 if (t >= tmin + CLOSE_TOLERANCE)
349 if (t > tmax) return(FALSE);
351 smin = SIDE_Y_0;
352 tmin = t;
354 else
357 * If intersection points are close to each other find out
358 * which side to use, i.e. is most probably hit. [DB 9/94]
361 if (t >= tmin - CLOSE_TOLERANCE)
363 if (D[Y] > fabs(D[X])) smin = SIDE_Y_0;
367 else
369 if ((P[Y] < box->bounds[0][Y]) || (P[Y] > box->bounds[1][Y]))
371 return(FALSE);
376 /* Now front/back */
378 if (D[Z] < -EPSILON)
380 t = (box->bounds[0][Z] - P[Z]) / D[Z];
382 if (t < tmin) return(FALSE);
384 if (t <= tmax - CLOSE_TOLERANCE)
386 smax = SIDE_Z_0;
387 tmax = t;
389 else
392 * If intersection points are close to each other find out
393 * which side to use, i.e. is most probably hit. [DB 9/94]
396 if (t <= tmax + CLOSE_TOLERANCE)
398 switch (smax)
400 case SIDE_X_0 :
401 case SIDE_X_1 : if (-D[Z] > fabs(D[X])) smax = SIDE_Z_0; break;
403 case SIDE_Y_0 :
404 case SIDE_Y_1 : if (-D[Z] > fabs(D[Y])) smax = SIDE_Z_0; break;
409 t = (box->bounds[1][Z] - P[Z]) / D[Z];
411 if (t >= tmin + CLOSE_TOLERANCE)
413 if (t > tmax) return(FALSE);
415 smin = SIDE_Z_1;
416 tmin = t;
418 else
421 * If intersection points are close to each other find out
422 * which side to use, i.e. is most probably hit. [DB 9/94]
425 if (t >= tmin - CLOSE_TOLERANCE)
427 switch (smin)
429 case SIDE_X_0 :
430 case SIDE_X_1 : if (-D[Z] > fabs(D[X])) smin = SIDE_Z_1; break;
432 case SIDE_Y_0 :
433 case SIDE_Y_1 : if (-D[Z] > fabs(D[Y])) smin = SIDE_Z_1; break;
438 else
440 if (D[Z] > EPSILON)
442 t = (box->bounds[1][Z] - P[Z]) / D[Z];
444 if (t < tmin) return(FALSE);
446 if (t <= tmax - CLOSE_TOLERANCE)
448 smax = SIDE_Z_1;
449 tmax = t;
451 else
454 * If intersection points are close to each other find out
455 * which side to use, i.e. is most probably hit. [DB 9/94]
458 if (t <= tmax + CLOSE_TOLERANCE)
460 switch (smax)
462 case SIDE_X_0 :
463 case SIDE_X_1 : if (D[Z] > fabs(D[X])) smax = SIDE_Z_1; break;
465 case SIDE_Y_0 :
466 case SIDE_Y_1 : if (D[Z] > fabs(D[Y])) smax = SIDE_Z_1; break;
471 t = (box->bounds[0][Z] - P[Z]) / D[Z];
473 if (t >= tmin + CLOSE_TOLERANCE)
475 if (t > tmax) return(FALSE);
477 smin = SIDE_Z_0;
478 tmin = t;
480 else
483 * If intersection points are close to each other find out
484 * which side to use, i.e. is most probably hit. [DB 9/94]
487 if (t >= tmin - CLOSE_TOLERANCE)
489 switch (smin)
491 case SIDE_X_0 :
492 case SIDE_X_1 : if (D[Z] > fabs(D[X])) smin = SIDE_Z_0; break;
494 case SIDE_Y_0 :
495 case SIDE_Y_1 : if (D[Z] > fabs(D[Y])) smin = SIDE_Z_0; break;
500 else
502 if ((P[Z] < box->bounds[0][Z]) || (P[Z] > box->bounds[1][Z]))
504 return(FALSE);
509 if (tmax < DEPTH_TOLERANCE)
511 return (FALSE);
514 *Depth1 = tmin;
515 *Depth2 = tmax;
517 *Side1 = smin;
518 *Side2 = smax;
520 return(TRUE);
525 /*****************************************************************************
527 * FUNCTION
529 * Inside_Box
531 * INPUT
533 * OUTPUT
535 * RETURNS
537 * AUTHOR
539 * Alexander Enzmann
541 * DESCRIPTION
545 * CHANGES
549 ******************************************************************************/
551 static int Inside_Box(VECTOR IPoint, OBJECT *Object)
553 VECTOR New_Point;
554 BOX *box = (BOX *) Object;
556 /* Transform the point into box space. */
558 if (box->Trans != NULL)
560 MInvTransPoint(New_Point, IPoint, box->Trans);
562 else
564 Assign_Vector(New_Point,IPoint);
567 /* Test to see if we are outside the box. */
569 if ((New_Point[X] < box->bounds[0][X]) || (New_Point[X] > box->bounds[1][X]))
571 return (Test_Flag(box, INVERTED_FLAG));
574 if ((New_Point[Y] < box->bounds[0][Y]) || (New_Point[Y] > box->bounds[1][Y]))
576 return (Test_Flag(box, INVERTED_FLAG));
579 if ((New_Point[Z] < box->bounds[0][Z]) || (New_Point[Z] > box->bounds[1][Z]))
581 return (Test_Flag(box, INVERTED_FLAG));
584 /* Inside the box. */
586 return (!Test_Flag(box, INVERTED_FLAG));
591 /*****************************************************************************
593 * FUNCTION
595 * Box_Normal
597 * INPUT
599 * OUTPUT
601 * RETURNS
603 * AUTHOR
605 * Alexander Enzmann
607 * DESCRIPTION
611 * CHANGES
615 ******************************************************************************/
617 static void Box_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
619 switch (Inter->i1)
621 case SIDE_X_0: Make_Vector(Result, -1.0, 0.0, 0.0); break;
622 case SIDE_X_1: Make_Vector(Result, 1.0, 0.0, 0.0); break;
623 case SIDE_Y_0: Make_Vector(Result, 0.0, -1.0, 0.0); break;
624 case SIDE_Y_1: Make_Vector(Result, 0.0, 1.0, 0.0); break;
625 case SIDE_Z_0: Make_Vector(Result, 0.0, 0.0, -1.0); break;
626 case SIDE_Z_1: Make_Vector(Result, 0.0, 0.0, 1.0); break;
628 default: Error("Unknown box side in Box_Normal().\n");
631 /* Transform the point into the boxes space. */
633 if (((BOX *)Object)->Trans != NULL)
635 MTransNormal(Result, Result, ((BOX *)Object)->Trans);
637 VNormalize(Result, Result);
643 /*****************************************************************************
645 * FUNCTION
647 * Translate_Box
649 * INPUT
651 * OUTPUT
653 * RETURNS
655 * AUTHOR
657 * Alexander Enzmann
659 * DESCRIPTION
663 * CHANGES
667 ******************************************************************************/
669 static void Translate_Box(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
671 if (((BOX *)Object)->Trans == NULL)
673 VAddEq(((BOX *)Object)->bounds[0], Vector);
675 VAddEq(((BOX *)Object)->bounds[1], Vector);
677 Compute_Box_BBox((BOX *)Object);
679 else
681 Transform_Box(Object, Trans);
687 /*****************************************************************************
689 * FUNCTION
691 * Rotate_Box
693 * INPUT
695 * OUTPUT
697 * RETURNS
699 * AUTHOR
701 * Alexander Enzmann
703 * DESCRIPTION
707 * CHANGES
711 ******************************************************************************/
713 static void Rotate_Box(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
715 Transform_Box(Object, Trans);
720 /*****************************************************************************
722 * FUNCTION
724 * Scale_Box
726 * INPUT
728 * OUTPUT
730 * RETURNS
732 * AUTHOR
734 * Alexander Enzmann
736 * DESCRIPTION
740 * CHANGES
744 ******************************************************************************/
746 static void Scale_Box(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
748 DBL temp;
749 BOX *Box = (BOX *)Object;
751 if (((BOX *)Object)->Trans == NULL)
753 VEvaluateEq(Box->bounds[0], Vector);
754 VEvaluateEq(Box->bounds[1], Vector);
756 if (Box->bounds[0][X] > Box->bounds[1][X])
758 temp = Box->bounds[0][X];
760 Box->bounds[0][X] = Box->bounds[1][X];
761 Box->bounds[1][X] = temp;
764 if (Box->bounds[0][Y] > Box->bounds[1][Y])
766 temp = Box->bounds[0][Y];
768 Box->bounds[0][Y] = Box->bounds[1][Y];
769 Box->bounds[1][Y] = temp;
772 if (Box->bounds[0][Z] > Box->bounds[1][Z])
774 temp = Box->bounds[0][Z];
776 Box->bounds[0][Z] = Box->bounds[1][Z];
777 Box->bounds[1][Z] = temp;
780 Compute_Box_BBox((BOX *)Object);
782 else
784 Transform_Box(Object, Trans);
790 /*****************************************************************************
792 * FUNCTION
794 * Invert_Box
796 * INPUT
798 * OUTPUT
800 * RETURNS
802 * AUTHOR
804 * Alexander Enzmann
806 * DESCRIPTION
810 * CHANGES
814 ******************************************************************************/
816 static void Invert_Box(OBJECT *Object)
818 Invert_Flag(Object, INVERTED_FLAG);
823 /*****************************************************************************
825 * FUNCTION
827 * Transform_Box
829 * INPUT
831 * OUTPUT
833 * RETURNS
835 * AUTHOR
837 * Alexander Enzmann
839 * DESCRIPTION
843 * CHANGES
847 ******************************************************************************/
849 static void Transform_Box(OBJECT *Object, TRANSFORM *Trans)
851 BOX *box = (BOX *)Object;
853 if (box->Trans == NULL)
855 box->Trans = Create_Transform();
858 Compose_Transforms(box->Trans, Trans);
860 Compute_Box_BBox(box);
865 /*****************************************************************************
867 * FUNCTION
869 * Create_Box
871 * INPUT
873 * OUTPUT
875 * RETURNS
877 * AUTHOR
879 * Alexander Enzmann
881 * DESCRIPTION
885 * CHANGES
889 ******************************************************************************/
891 BOX *Create_Box()
893 BOX *New;
895 New = (BOX *)POV_MALLOC(sizeof(BOX), "box");
897 INIT_OBJECT_FIELDS(New, BOX_OBJECT, &Box_Methods)
899 Make_Vector(New->bounds[0], -1.0, -1.0, -1.0);
900 Make_Vector(New->bounds[1], 1.0, 1.0, 1.0);
902 Make_BBox(New->BBox, -1.0, -1.0, -1.0, 2.0, 2.0, 2.0);
904 New->Trans = NULL;
906 return (New);
911 /*****************************************************************************
913 * FUNCTION
915 * Copy_Box
917 * INPUT
919 * OUTPUT
921 * RETURNS
923 * AUTHOR
925 * Alexander Enzmann
927 * DESCRIPTION
931 * CHANGES
935 ******************************************************************************/
937 BOX *Copy_Box(OBJECT *Object)
939 BOX *New;
941 New = Create_Box();
943 /* Copy box. */
945 *New = *((BOX *)Object);
947 New->Trans = Copy_Transform(((BOX *)Object)->Trans);
949 return (New);
954 /*****************************************************************************
956 * FUNCTION
958 * Destroy_Box
960 * INPUT
962 * OUTPUT
964 * RETURNS
966 * AUTHOR
968 * Alexander Enzmann
970 * DESCRIPTION
974 * CHANGES
978 ******************************************************************************/
980 void Destroy_Box(OBJECT *Object)
982 Destroy_Transform(((BOX *)Object)->Trans);
984 POV_FREE (Object);
989 /*****************************************************************************
991 * FUNCTION
993 * Compute_Box_BBox
995 * INPUT
997 * Box - Box
999 * OUTPUT
1001 * Box
1003 * RETURNS
1005 * AUTHOR
1007 * Dieter Bayer
1009 * DESCRIPTION
1011 * Calculate the bounding box of a box.
1013 * CHANGES
1015 * Aug 1994 : Creation.
1017 ******************************************************************************/
1019 void Compute_Box_BBox(BOX *Box)
1021 Assign_BBox_Vect(Box->BBox.Lower_Left, Box->bounds[0]);
1023 VSub(Box->BBox.Lengths, Box->bounds[1], Box->bounds[0]);
1025 if (Box->Trans != NULL)
1027 Recompute_BBox(&Box->BBox, Box->Trans);