Attempt to fix nightly build.
[AROS-Contrib.git] / gfx / povray / cones.c
blob20af31183ba6e5aef5a378d5eb16f16309f65a1e
1 /****************************************************************************
2 * cones.c
4 * This module implements the cone primitive.
5 * This file was written by Alexander Enzmann. He wrote the code for
6 * cones 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 "cones.h"
32 #include "matrices.h"
33 #include "objects.h"
37 /*****************************************************************************
38 * Local preprocessor defines
39 ******************************************************************************/
41 #define Cone_Tolerance 1.0e-6
43 #define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
45 /* Part of the cone/cylinder hit. [DB 9/94] */
47 #define BASE_HIT 1
48 #define CAP_HIT 2
49 #define SIDE_HIT 3
53 /*****************************************************************************
54 * Local typedefs
55 ******************************************************************************/
57 typedef struct Cone_Intersection_Structure CONE_INT;
59 struct Cone_Intersection_Structure
61 DBL d; /* Distance of intersection point */
62 int t; /* Type of intersection: base/cap plane or side */
67 /*****************************************************************************
68 * Static functions
69 ******************************************************************************/
71 static int intersect_cone (RAY *Ray, CONE *Cone, CONE_INT *Depths);
72 static void Destroy_Cone (OBJECT *Object);
73 static int All_Cone_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
74 static int Inside_Cone (VECTOR point, OBJECT *Object);
75 static void Cone_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
76 static CONE *Copy_Cone (OBJECT *Object);
77 static void Translate_Cone (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
78 static void Rotate_Cone (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
79 static void Scale_Cone (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
80 static void Transform_Cone (OBJECT *Object, TRANSFORM *Trans);
81 static void Invert_Cone (OBJECT *Object);
84 /*****************************************************************************
85 * Local variables
86 ******************************************************************************/
88 static METHODS Cone_Methods =
90 All_Cone_Intersections,
91 Inside_Cone, Cone_Normal,
92 (COPY_METHOD)Copy_Cone, Translate_Cone, Rotate_Cone, Scale_Cone, Transform_Cone,
93 Invert_Cone, Destroy_Cone
98 /*****************************************************************************
100 * FUNCTION
102 * All_Cone_Intersections
104 * INPUT
106 * OUTPUT
108 * RETURNS
110 * AUTHOR
112 * Alexander Enzmann
114 * DESCRIPTION
118 * CHANGES
122 ******************************************************************************/
124 static int All_Cone_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
126 int Intersection_Found, cnt, i;
127 VECTOR IPoint;
128 CONE_INT I[4];
130 Intersection_Found = FALSE;
132 if ((cnt = intersect_cone(Ray, (CONE *)Object, I)) != 0)
134 for (i = 0; i < cnt; i++)
136 VEvaluateRay(IPoint, Ray->Initial, I[i].d, Ray->Direction);
138 if (Point_In_Clip(IPoint, Object->Clip))
140 push_entry_i1(I[i].d,IPoint,Object,I[i].t,Depth_Stack);
142 Intersection_Found = TRUE;
147 return (Intersection_Found);
152 /*****************************************************************************
154 * FUNCTION
156 * intersect_cone
158 * INPUT
160 * OUTPUT
162 * RETURNS
164 * AUTHOR
166 * Alexander Enzmann
168 * DESCRIPTION
172 * CHANGES
176 ******************************************************************************/
178 static int intersect_cone(RAY *Ray, CONE *Cone, CONE_INT *Intersection)
180 int i = 0;
181 DBL a, b, c, z, t1, t2, len;
182 DBL d;
183 VECTOR P, D;
185 Increase_Counter(stats[Ray_Cone_Tests]);
187 /* Transform the ray into the cones space */
189 MInvTransPoint(P, Ray->Initial, Cone->Trans);
190 MInvTransDirection(D, Ray->Direction, Cone->Trans);
192 VLength(len, D);
193 VInverseScaleEq(D, len);
195 if (Test_Flag(Cone, CYLINDER_FLAG))
197 /* Solve intersections with a cylinder */
199 a = D[X] * D[X] + D[Y] * D[Y];
201 if (a > EPSILON)
203 b = P[X] * D[X] + P[Y] * D[Y];
205 c = P[X] * P[X] + P[Y] * P[Y] - 1.0;
207 d = b * b - a * c;
209 if (d >= 0.0)
211 d = sqrt(d);
213 t1 = (-b + d) / a;
214 t2 = (-b - d) / a;
216 z = P[Z] + t1 * D[Z];
218 if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= 0.0) && (z <= 1.0))
220 Intersection[i].d = t1 / len;
221 Intersection[i++].t = SIDE_HIT;
224 z = P[Z] + t2 * D[Z];
226 if ((t2 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= 0.0) && (z <= 1.0))
228 Intersection[i].d = t2 / len;
229 Intersection[i++].t = SIDE_HIT;
234 else
236 /* Solve intersections with a cone */
238 a = D[X] * D[X] + D[Y] * D[Y] - D[Z] * D[Z];
240 b = D[X] * P[X] + D[Y] * P[Y] - D[Z] * P[Z];
242 c = P[X] * P[X] + P[Y] * P[Y] - P[Z] * P[Z];
244 if (fabs(a) < EPSILON)
246 if (fabs(b) > EPSILON)
248 /* One intersection */
250 t1 = -0.5 * c / b;
252 z = P[Z] + t1 * D[Z];
254 if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
256 Intersection[i].d = t1 / len;
257 Intersection[i++].t = SIDE_HIT;
261 else
263 /* Check hits against the side of the cone */
265 d = b * b - a * c;
267 if (d >= 0.0)
269 d = sqrt(d);
271 t1 = (-b - d) / a;
272 t2 = (-b + d) / a;
274 z = P[Z] + t1 * D[Z];
276 if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
278 Intersection[i].d = t1 / len;
279 Intersection[i++].t = SIDE_HIT;
282 z = P[Z] + t2 * D[Z];
284 if ((t2 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
286 Intersection[i].d = t2 / len;
287 Intersection[i++].t = SIDE_HIT;
293 if (Test_Flag(Cone, CLOSED_FLAG) && (fabs(D[Z]) > EPSILON))
295 d = (1.0 - P[Z]) / D[Z];
297 a = (P[X] + d * D[X]);
299 b = (P[Y] + d * D[Y]);
301 if (((Sqr(a) + Sqr(b)) <= 1.0) && (d > Cone_Tolerance) && (d < Max_Distance))
303 Intersection[i].d = d / len;
304 Intersection[i++].t = CAP_HIT;
307 d = (Cone->dist - P[Z]) / D[Z];
309 a = (P[X] + d * D[X]);
311 b = (P[Y] + d * D[Y]);
313 if ((Sqr(a) + Sqr(b)) <= (Test_Flag(Cone, CYLINDER_FLAG) ? 1.0 : Sqr(Cone->dist))
314 && (d > Cone_Tolerance) && (d < Max_Distance))
316 Intersection[i].d = d / len;
317 Intersection[i++].t = BASE_HIT;
321 if (i)
323 Increase_Counter(stats[Ray_Cone_Tests_Succeeded]);
326 return (i);
331 /*****************************************************************************
333 * FUNCTION
335 * Inside_Cone
337 * INPUT
339 * OUTPUT
341 * RETURNS
343 * AUTHOR
345 * Alexander Enzmann
347 * DESCRIPTION
351 * CHANGES
355 ******************************************************************************/
357 static int Inside_Cone(VECTOR IPoint, OBJECT *Object)
359 CONE *Cone = (CONE *)Object;
360 DBL w2, z2, offset = (Test_Flag(Cone, CLOSED_FLAG) ? -EPSILON : EPSILON);
361 VECTOR New_Point;
363 /* Transform the point into the cones space */
365 MInvTransPoint(New_Point, IPoint, Cone->Trans);
367 /* Test to see if we are inside the cone */
369 w2 = New_Point[X] * New_Point[X] + New_Point[Y] * New_Point[Y];
371 if (Test_Flag(Cone, CYLINDER_FLAG))
373 /* Check to see if we are inside a cylinder */
375 if ((w2 > 1.0 + offset) ||
376 (New_Point[Z] < 0.0 - offset) ||
377 (New_Point[Z] > 1.0 + offset))
379 return (Test_Flag(Cone, INVERTED_FLAG));
381 else
383 return (!Test_Flag(Cone, INVERTED_FLAG));
386 else
388 /* Check to see if we are inside a cone */
390 z2 = New_Point[Z] * New_Point[Z];
392 if ((w2 > z2 + offset) ||
393 (New_Point[Z] < Cone->dist - offset) ||
394 (New_Point[Z] > 1.0+offset))
396 return (Test_Flag(Cone, INVERTED_FLAG));
398 else
400 return (!Test_Flag(Cone, INVERTED_FLAG));
407 /*****************************************************************************
409 * FUNCTION
411 * Cone_Normal
413 * INPUT
415 * OUTPUT
417 * RETURNS
419 * AUTHOR
421 * Alexander Enzmann
423 * DESCRIPTION
427 * CHANGES
431 ******************************************************************************/
433 static void Cone_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
435 CONE *Cone = (CONE *)Object;
437 /* Transform the point into the cones space */
439 MInvTransPoint(Result, Inter->IPoint, Cone->Trans);
441 /* Calculating the normal is real simple in canonical cone space */
443 switch (Inter->i1)
445 case SIDE_HIT:
447 if (Test_Flag(Cone, CYLINDER_FLAG))
449 Result[Z] = 0.0;
451 else
453 Result[Z] = -Result[Z];
456 break;
458 case BASE_HIT:
460 Make_Vector(Result, 0.0, 0.0, -1.0)
462 break;
464 case CAP_HIT:
466 Make_Vector(Result, 0.0, 0.0, 1.0)
468 break;
471 /* Transform the point out of the cones space */
473 MTransNormal(Result, Result, Cone->Trans);
475 VNormalize(Result, Result);
480 /*****************************************************************************
482 * FUNCTION
484 * Translate_Cone
486 * INPUT
488 * OUTPUT
490 * RETURNS
492 * AUTHOR
494 * Alexander Enzmann
496 * DESCRIPTION
500 * CHANGES
504 ******************************************************************************/
506 static void Translate_Cone(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
508 Transform_Cone(Object, Trans);
513 /*****************************************************************************
515 * FUNCTION
517 * Rotate_Cone
519 * INPUT
521 * OUTPUT
523 * RETURNS
525 * AUTHOR
527 * Alexander Enzmann
529 * DESCRIPTION
533 * CHANGES
537 ******************************************************************************/
539 static void Rotate_Cone(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
541 Transform_Cone(Object, Trans);
546 /*****************************************************************************
548 * FUNCTION
550 * Scale_Cone
552 * INPUT
554 * OUTPUT
556 * RETURNS
558 * AUTHOR
560 * Alexander Enzmann
562 * DESCRIPTION
566 * CHANGES
570 ******************************************************************************/
572 static void Scale_Cone(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
574 Transform_Cone(Object, Trans);
579 /*****************************************************************************
581 * FUNCTION
583 * Transform_Cone
585 * INPUT
587 * OUTPUT
589 * RETURNS
591 * AUTHOR
593 * Alexander Enzmann
595 * DESCRIPTION
599 * CHANGES
603 ******************************************************************************/
605 static void Transform_Cone(OBJECT *Object, TRANSFORM *Trans)
607 CONE *Cone = (CONE *)Object;
609 Compose_Transforms(Cone->Trans, Trans);
611 Compute_Cone_BBox(Cone);
616 /*****************************************************************************
618 * FUNCTION
620 * Invert_Cone
622 * INPUT
624 * OUTPUT
626 * RETURNS
628 * AUTHOR
630 * Alexander Enzmann
632 * DESCRIPTION
636 * CHANGES
640 ******************************************************************************/
642 static void Invert_Cone(OBJECT *Object)
644 Invert_Flag(Object, INVERTED_FLAG);
649 /*****************************************************************************
651 * FUNCTION
653 * Create_Cone
655 * INPUT
657 * OUTPUT
659 * RETURNS
661 * AUTHOR
663 * Alexander Enzmann
665 * DESCRIPTION
669 * CHANGES
673 ******************************************************************************/
675 CONE *Create_Cone()
677 CONE *New;
679 New = (CONE *)POV_MALLOC(sizeof(CONE), "cone");
681 INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
683 Make_Vector(New->apex, 0.0, 0.0, 1.0);
684 Make_Vector(New->base, 0.0, 0.0, 0.0);
686 New->apex_radius = 1.0;
687 New->base_radius = 0.0;
689 New->dist = 0.0;
691 New->Trans = Create_Transform();
693 /* Cone/Cylinder has capped ends by default. */
695 Set_Flag(New, CLOSED_FLAG);
697 /* Default bounds */
699 Make_BBox(New->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
701 return (New);
706 /*****************************************************************************
708 * FUNCTION
710 * Copy_Cone
712 * INPUT
714 * OUTPUT
716 * RETURNS
718 * AUTHOR
720 * Alexander Enzmann
722 * DESCRIPTION
726 * CHANGES
730 ******************************************************************************/
732 static CONE *Copy_Cone(OBJECT *Object)
734 CONE *New;
736 New = Create_Cone();
738 /* Get rid of the transformation created in Create_Cone(). */
740 Destroy_Transform(New->Trans);
742 /* Copy cone. */
744 *New = *((CONE *)Object);
746 New->Trans = Copy_Transform(((CONE *)Object)->Trans);
748 return (New);
753 /*****************************************************************************
755 * FUNCTION
757 * Create_Cylinder
759 * INPUT
761 * OUTPUT
763 * RETURNS
765 * AUTHOR
767 * Alexander Enzmann
769 * DESCRIPTION
773 * CHANGES
777 ******************************************************************************/
779 CONE *Create_Cylinder()
781 CONE *New;
783 New = (CONE *)POV_MALLOC(sizeof(CONE), "cone");
785 INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
787 Make_Vector(New->apex, 0.0, 0.0, 1.0);
788 Make_Vector(New->base, 0.0, 0.0, 0.0);
790 New->apex_radius = 1.0;
791 New->base_radius = 1.0;
792 New->dist = 0.0;
794 New->Trans = Create_Transform();
796 Set_Flag(New, CYLINDER_FLAG); /* This is a cylinder. */
797 Set_Flag(New, CLOSED_FLAG); /* Has capped ends. */
799 /* Default bounds */
801 Make_BBox(New->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
803 return (New);
808 /*****************************************************************************
810 * FUNCTION
812 * Compute_Cone_Data
814 * INPUT
816 * OUTPUT
818 * RETURNS
820 * AUTHOR
822 * Alexander Enzmann
824 * DESCRIPTION
828 * CHANGES
830 * Feb 1996: check for equal sized ends (cylinder) first [AED]
832 ******************************************************************************/
834 void Compute_Cone_Data(OBJECT *Object)
836 DBL tlen, len, tmpf;
837 VECTOR tmpv, axis, origin;
838 CONE *Cone = (CONE *)Object;
840 /* Process the primitive specific information */
842 if (fabs(Cone->apex_radius - Cone->base_radius) < EPSILON)
844 /* What we are dealing with here is really a cylinder */
846 Set_Flag(Cone, CYLINDER_FLAG);
848 Compute_Cylinder_Data(Object);
850 return;
853 if (Cone->apex_radius < Cone->base_radius)
855 /* Want the bigger end at the top */
857 Assign_Vector(tmpv,Cone->base);
858 Assign_Vector(Cone->base,Cone->apex);
859 Assign_Vector(Cone->apex,tmpv);
861 tmpf = Cone->base_radius;
862 Cone->base_radius = Cone->apex_radius;
863 Cone->apex_radius = tmpf;
866 /* Find the axis and axis length */
868 VSub(axis, Cone->apex, Cone->base);
870 VLength(len, axis);
872 if (len < EPSILON)
874 Error("Degenerate cone/cylinder.\n");
876 else
878 VInverseScaleEq(axis, len)
881 /* Determine alignment */
883 tmpf = Cone->base_radius * len / (Cone->apex_radius - Cone->base_radius);
885 VScale(origin, axis, tmpf);
887 VSub(origin, Cone->base, origin);
889 tlen = tmpf + len;
891 Cone->dist = tmpf / tlen;
893 Compute_Coordinate_Transform(Cone->Trans, origin, axis, Cone->apex_radius, tlen);
895 /* Recalculate the bounds */
897 Compute_Cone_BBox(Cone);
902 /*****************************************************************************
904 * FUNCTION
906 * Compute_Cylinder_Data
908 * INPUT
910 * OUTPUT
912 * RETURNS
914 * AUTHOR
916 * Alexander Enzmann
918 * DESCRIPTION
922 * CHANGES
926 ******************************************************************************/
928 void Compute_Cylinder_Data(OBJECT *Object)
930 DBL tmpf;
931 VECTOR axis;
932 CONE *Cone = (CONE *)Object;
934 VSub(axis, Cone->apex, Cone->base);
936 VLength(tmpf, axis);
938 if (tmpf < EPSILON)
940 Error("Degenerate cylinder, base point = apex point.\n");
942 else
944 VInverseScaleEq(axis, tmpf)
946 Compute_Coordinate_Transform(Cone->Trans, Cone->base, axis, Cone->apex_radius, tmpf);
949 Cone->dist = 0.0;
951 /* Recalculate the bounds */
953 Compute_Cone_BBox(Cone);
959 /*****************************************************************************
961 * FUNCTION
963 * Destroy_Cone
965 * INPUT
967 * OUTPUT
969 * RETURNS
971 * AUTHOR
973 * Alexander Enzmann
975 * DESCRIPTION
979 * CHANGES
983 ******************************************************************************/
985 static void Destroy_Cone(OBJECT *Object)
987 Destroy_Transform(((CONE *)Object)->Trans);
989 POV_FREE (Object);
994 /*****************************************************************************
996 * FUNCTION
998 * Compute_Cone_BBox
1000 * INPUT
1002 * Cone - Cone/Cylinder
1004 * OUTPUT
1006 * Cone
1008 * RETURNS
1010 * AUTHOR
1012 * Dieter Bayer
1014 * DESCRIPTION
1016 * Calculate the bounding box of a cone or cylinder.
1018 * CHANGES
1020 * Aug 1994 : Creation.
1022 ******************************************************************************/
1024 void Compute_Cone_BBox(CONE *Cone)
1026 Make_BBox(Cone->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
1028 Recompute_BBox(&Cone->BBox, Cone->Trans);