disable the unrecognized nls and x flags
[AROS-Contrib.git] / gfx / povray / fractal.c
blob40ec74cc7a0fac0a51caba26c3c0ab314337c7ef
1 /*****************************************************************************
2 * fractal.c
4 * This module implements the fractal sets primitive.
6 * This file was written by Pascal Massimino.
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 "matrices.h"
32 #include "objects.h"
33 #include "spheres.h"
34 #include "fractal.h"
35 #include "quatern.h"
36 #include "hcmplx.h"
40 /*****************************************************************************
41 * Local preprocessor defines
42 ******************************************************************************/
44 #ifndef Fractal_Tolerance
45 #define Fractal_Tolerance 1e-7
46 #endif
50 /*****************************************************************************
51 * Local typedefs
52 ******************************************************************************/
56 /*****************************************************************************
57 * Static functions
58 ******************************************************************************/
60 static int All_Fractal_Intersections (OBJECT * Object, RAY * Ray, ISTACK * Depth_Stack);
61 static int Inside_Fractal (VECTOR IPoint, OBJECT * Object);
62 static void Fractal_Normal (VECTOR Result, OBJECT * Object, INTERSECTION * Intersect);
63 static FRACTAL *Copy_Fractal (OBJECT * Object);
64 static void Translate_Fractal (OBJECT * Object, VECTOR Vector, TRANSFORM *Trans);
65 static void Rotate_Fractal (OBJECT * Object, VECTOR Vector, TRANSFORM *Trans);
66 static void Scale_Fractal (OBJECT * Object, VECTOR Vector, TRANSFORM *Trans);
67 static void Transform_Fractal (OBJECT * Object, TRANSFORM * Trans);
68 static void Invert_Fractal (OBJECT * Object);
69 static void Destroy_Fractal (OBJECT * Object);
70 static void Compute_Fractal_BBox (FRACTAL * Fractal);
72 /*****************************************************************************
73 * Local variables
74 ******************************************************************************/
76 static METHODS Fractal_Methods =
78 All_Fractal_Intersections,
79 Inside_Fractal, Fractal_Normal,
80 (COPY_METHOD)Copy_Fractal,
81 Translate_Fractal, Rotate_Fractal,
82 Scale_Fractal, Transform_Fractal, Invert_Fractal,
83 Destroy_Fractal
86 static int Allocated_Iteration_Stack_Length = 0;
88 DBL *Sx = NULL, *Sy = NULL, *Sz = NULL, *Sw = NULL;
89 DBL Precision;
90 VECTOR Direction;
92 static COMPLEX_FUNCTION_METHOD Complex_Function_List[] =
94 /* must match STYPE list in fractal.h */
95 Complex_Exp,
96 Complex_Log,
97 Complex_Sin,
98 Complex_ASin,
99 Complex_Cos,
100 Complex_ACos,
101 Complex_Tan,
102 Complex_ATan,
103 Complex_Sinh,
104 Complex_ASinh,
105 Complex_Cosh,
106 Complex_ACosh,
107 Complex_Tanh,
108 Complex_ATanh,
109 Complex_Pwr
112 /*****************************************************************************
114 * FUNCTION
116 * INPUT
118 * OUTPUT
120 * RETURNS
122 * AUTHOR
124 * Pascal Massimino
126 * DESCRIPTION
130 * CHANGES
132 * Dec 1994 : Creation.
134 ******************************************************************************/
136 static int All_Fractal_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
138 int Intersection_Found;
139 int Last = 0;
140 int CURRENT, NEXT;
141 DBL Depth, Depth_Max;
142 DBL Dist, Dist_Next, Len;
144 VECTOR IPoint, Mid_Point, Next_Point, Real_Pt;
145 VECTOR Real_Normal, F_Normal;
146 RAY New_Ray;
147 FRACTAL *Fractal = (FRACTAL *) Object;
149 Increase_Counter(stats[Ray_Fractal_Tests]);
151 Intersection_Found = FALSE;
152 Precision = Fractal->Precision;
154 /* Get into Fractal's world. */
156 if (Fractal->Trans != NULL)
158 MInvTransDirection(Direction, Ray->Direction, Fractal->Trans);
159 VDot(Len, Direction, Direction);
161 if (Len == 0.0)
163 return (FALSE);
166 if (Len != 1.0)
168 Len = 1.0 / sqrt(Len);
169 VScaleEq(Direction, Len);
172 Assign_Vector(New_Ray.Direction, Direction);
173 MInvTransPoint(New_Ray.Initial, Ray->Initial, Fractal->Trans);
175 else
177 Assign_Vector(Direction, Ray->Direction);
178 New_Ray = *Ray;
179 Len = 1.0;
182 /* Bound fractal. */
184 if (!F_Bound(&New_Ray, Fractal, &Depth, &Depth_Max))
186 return (FALSE);
189 if (Depth_Max < Fractal_Tolerance)
191 return (FALSE);
194 if (Depth < Fractal_Tolerance)
196 Depth = Fractal_Tolerance;
199 /* Jump to starting point */
201 VScale(Next_Point, Direction, Depth);
202 VAddEq(Next_Point, New_Ray.Initial);
204 CURRENT = D_Iteration(Next_Point, Fractal, &Dist);
206 /* Light ray starting inside ? */
208 if (CURRENT)
210 VAddScaledEq(Next_Point, 2.0 * Fractal_Tolerance, Direction);
212 Depth += 2.0 * Fractal_Tolerance;
214 if (Depth > Depth_Max)
216 return (FALSE);
219 CURRENT = D_Iteration(Next_Point, Fractal, &Dist);
222 /* Ok. Trace it */
224 while (Depth < Depth_Max)
227 * Get close to the root: Advance with Next_Point, keeping track of last
228 * position in IPoint...
231 while (1)
233 if (Dist < Precision)
235 Dist = Precision;
238 Depth += Dist;
240 if (Depth > Depth_Max)
242 if (Intersection_Found)
244 Increase_Counter(stats[Ray_Fractal_Tests_Succeeded]);
247 return (Intersection_Found);
250 Assign_Vector(IPoint, Next_Point);
251 VAddScaledEq(Next_Point, Dist, Direction);
253 NEXT = D_Iteration(Next_Point, Fractal, &Dist_Next);
255 if (NEXT != CURRENT)
257 /* Set surface was crossed... */
259 Depth -= Dist;
260 break;
262 else
264 Dist = Dist_Next; /* not reached */
268 /* then, polish the root via bisection method... */
270 while (Dist > Fractal_Tolerance)
272 Dist *= 0.5;
273 VAddScaled(Mid_Point, IPoint, Dist, Direction);
275 Last = Iteration(Mid_Point, Fractal);
277 if (Last == CURRENT)
279 Assign_Vector(IPoint, Mid_Point);
281 Depth += Dist;
283 if (Depth > Depth_Max)
285 if (Intersection_Found)
287 Increase_Counter(stats[Ray_Fractal_Tests_Succeeded]);
290 return (Intersection_Found);
295 if (CURRENT == FALSE) /* Mid_Point isn't inside the set */
297 VAddScaledEq(IPoint, Dist, Direction);
299 Depth += Dist;
301 Iteration(IPoint, Fractal);
303 else
305 if (Last != CURRENT)
307 Iteration(IPoint, Fractal);
311 if (Fractal->Trans != NULL)
313 MTransPoint(Real_Pt, IPoint, Fractal->Trans);
314 Normal_Calc(Fractal, F_Normal);
315 MTransNormal(Real_Normal, F_Normal, Fractal->Trans);
317 else
319 Assign_Vector(Real_Pt, IPoint);
320 Normal_Calc(Fractal, Real_Normal);
323 if (Point_In_Clip(Real_Pt, Object->Clip))
325 VNormalize(Real_Normal, Real_Normal);
326 push_normal_entry(Depth * Len, Real_Pt, Real_Normal, Object, Depth_Stack);
327 Intersection_Found = TRUE;
329 /* If fractal isn't used with CSG we can exit now. */
331 if (!(Fractal->Type & IS_CHILD_OBJECT))
333 break;
337 /* Start over where work was left */
339 Assign_Vector(IPoint, Next_Point);
340 Dist = Dist_Next;
341 CURRENT = NEXT;
345 if (Intersection_Found)
347 Increase_Counter(stats[Ray_Fractal_Tests_Succeeded]);
349 return (Intersection_Found);
352 /*****************************************************************************
354 * FUNCTION
356 * INPUT
358 * OUTPUT
360 * RETURNS
362 * AUTHOR
364 * Pascal Massimino
366 * DESCRIPTION
370 * CHANGES
372 * Dec 1994 : Creation.
374 ******************************************************************************/
376 static int Inside_Fractal(VECTOR IPoint, OBJECT *Object)
378 FRACTAL *Fractal = (FRACTAL *) Object;
379 int Result;
380 static VECTOR New_Point;
382 if (Fractal->Trans != NULL)
384 MInvTransPoint(New_Point, IPoint, Fractal->Trans);
386 Result = Iteration(New_Point, Fractal);
388 else
390 Result = Iteration(IPoint, Fractal);
393 if (Fractal->Inverted)
395 return (!Result);
397 else
399 return (Result);
403 /*****************************************************************************
405 * FUNCTION
407 * INPUT
409 * OUTPUT
411 * RETURNS
413 * AUTHOR
415 * Pascal Massimino
417 * DESCRIPTION
421 * CHANGES
423 * Dec 1994 : Creation.
425 ******************************************************************************/
427 static void Fractal_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Intersect)
429 Assign_Vector(Result, Intersect->INormal);
432 /*****************************************************************************
434 * FUNCTION
436 * INPUT
438 * OUTPUT
440 * RETURNS
442 * AUTHOR
444 * Pascal Massimino
446 * DESCRIPTION
450 * CHANGES
452 * Dec 1994 : Creation.
454 ******************************************************************************/
456 static void Translate_Fractal(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
458 Transform_Fractal(Object, Trans);
461 /*****************************************************************************
463 * FUNCTION
465 * INPUT
467 * OUTPUT
469 * RETURNS
471 * AUTHOR
473 * Pascal Massimino
475 * DESCRIPTION
479 * CHANGES
481 * Dec 1994 : Creation.
483 ******************************************************************************/
485 static void Rotate_Fractal(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
487 Transform_Fractal(Object, Trans);
490 /*****************************************************************************
492 * FUNCTION
494 * INPUT
496 * OUTPUT
498 * RETURNS
500 * AUTHOR
502 * Pascal Massimino
504 * DESCRIPTION
508 * CHANGES
510 * Dec 1994 : Creation.
512 ******************************************************************************/
514 static void Scale_Fractal(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
516 Transform_Fractal(Object, Trans);
519 /*****************************************************************************
521 * FUNCTION
523 * INPUT
525 * OUTPUT
527 * RETURNS
529 * AUTHOR
531 * Pascal Massimino
533 * DESCRIPTION
537 * CHANGES
539 * Dec 1994 : Creation.
540 * Mar 1996 : Moved call to Recompute_BBox to Compute_Fractal_BBox() (TW)
542 ******************************************************************************/
544 static void Transform_Fractal(OBJECT *Object, TRANSFORM *Trans)
546 FRACTAL *Fractal = (FRACTAL *) Object;
548 if (((FRACTAL *) Object)->Trans == NULL)
550 ((FRACTAL *) Object)->Trans = Create_Transform();
553 Compose_Transforms(Fractal->Trans, Trans);
555 Compute_Fractal_BBox((FRACTAL *) Object);
558 /*****************************************************************************
560 * FUNCTION
562 * INPUT
564 * OUTPUT
566 * RETURNS
568 * AUTHOR
570 * Pascal Massimino
572 * DESCRIPTION
576 * CHANGES
578 * Dec 1994 : Creation.
580 ******************************************************************************/
582 static void Invert_Fractal(OBJECT *Object)
584 ((FRACTAL *) Object)->Inverted ^= TRUE;
587 /*****************************************************************************
589 * FUNCTION
591 * INPUT
593 * OUTPUT
595 * RETURNS
597 * AUTHOR
599 * Pascal Massimino
601 * DESCRIPTION
605 * CHANGES
607 * Dec 1994 : Creation.
608 * Mar 1996 : Added call to recompute_BBox() to bottom (TW)
610 ******************************************************************************/
612 static void Compute_Fractal_BBox(FRACTAL *Fractal)
614 DBL R;
616 switch (Fractal->Algebra)
618 case QUATERNION_TYPE:
620 R = 1.0 + sqrt(Sqr(Fractal->Julia_Parm[X]) + Sqr(Fractal->Julia_Parm[Y]) + Sqr(Fractal->Julia_Parm[Z]) + Sqr(Fractal->Julia_Parm[T]));
621 R += Fractal_Tolerance; /* fix bug when Julia_Parameter exactly 0 */
623 if (R > 2.0)
625 R = 2.0;
628 Fractal->Exit_Value = Sqr(R);
630 break;
632 case HYPERCOMPLEX_TYPE:
633 default:
635 R = 4.0;
637 Fractal->Exit_Value = 16.0;
639 break;
642 Fractal->Radius_Squared = Sqr(R);
644 Fractal->Inverted = FALSE;
646 Make_BBox(Fractal->BBox, -R, -R, -R, 2.0 * R, 2.0 * R, 2.0 * R);
648 Recompute_BBox(&Fractal->BBox, Fractal->Trans);
651 /*****************************************************************************
653 * FUNCTION
655 * INPUT
657 * OUTPUT
659 * RETURNS
661 * AUTHOR
663 * Pascal Massimino
665 * DESCRIPTION
669 * CHANGES
671 * Dec 1994 : Creation.
673 ******************************************************************************/
675 FRACTAL *Create_Fractal()
677 FRACTAL *New;
679 New = (FRACTAL *) POV_MALLOC(sizeof(FRACTAL), "Fractal Set");
681 INIT_OBJECT_FIELDS(New, BASIC_OBJECT, &Fractal_Methods)
683 New->Trans = NULL;
685 Make_Vector(New->Center, 0.0, 0.0, 0.0);
687 New->Julia_Parm[X] = 1.0;
688 New->Julia_Parm[Y] = 0.0;
689 New->Julia_Parm[Z] = 0.0;
690 New->Julia_Parm[T] = 0.0;
692 New->Slice[X] = 0.0;
693 New->Slice[Y] = 0.0;
694 New->Slice[Z] = 0.0;
695 New->Slice[T] = 1.0;
696 New->SliceDist = 0.0;
698 New->Exit_Value = 4.0;
700 New->n = 20;
702 New->Precision = 1.0 / 20.0;
704 New->Inverted = FALSE;
706 New->Algebra = QUATERNION_TYPE;
708 New->Sub_Type = SQR_STYPE;
710 New->Bound = NULL;
712 New->Clip = NULL;
714 New->Normal_Calc_Method = NULL;
715 New->Iteration_Method = NULL;
716 New->D_Iteration_Method = NULL;
717 New->F_Bound_Method = NULL;
718 New->Complex_Function_Method = NULL;
720 New->Radius_Squared = 0.0;
721 New->exponent.x = 0.0;
722 New->exponent.y = 0.0;
724 return (New);
727 /*****************************************************************************
729 * FUNCTION
731 * INPUT
733 * OUTPUT
735 * RETURNS
737 * AUTHOR
739 * Pascal Massimino
741 * DESCRIPTION
745 * CHANGES
747 * Dec 1994 : Creation.
749 ******************************************************************************/
751 static FRACTAL *Copy_Fractal(OBJECT *Object)
753 FRACTAL *New;
755 New = Create_Fractal();
757 *New = *((FRACTAL *) Object);
759 New->Trans = Copy_Transform(((FRACTAL *) Object)->Trans);
761 return (New);
764 /*****************************************************************************
766 * FUNCTION
768 * INPUT
770 * OUTPUT
772 * RETURNS
774 * AUTHOR
776 * Pascal Massimino
778 * DESCRIPTION
782 * CHANGES
784 * Dec 1994 : Creation.
786 ******************************************************************************/
788 static void Destroy_Fractal(OBJECT *Object)
790 Destroy_Transform(((FRACTAL *) Object)->Trans);
791 POV_FREE(Object);
794 /*****************************************************************************
796 * FUNCTION
798 * INPUT
800 * OUTPUT
802 * RETURNS
804 * AUTHOR
806 * Pascal Massimino
808 * DESCRIPTION
812 * CHANGES
814 * Dec 1994 : Creation.
816 ******************************************************************************/
818 void SetUp_Fractal(FRACTAL *Fractal)
820 switch (Fractal->Algebra)
822 case QUATERNION_TYPE:
824 switch(Fractal->Sub_Type)
826 case CUBE_STYPE:
827 Fractal->Iteration_Method = Iteration_z3;
828 Fractal->Normal_Calc_Method = Normal_Calc_z3;
829 Fractal->D_Iteration_Method = D_Iteration_z3;
830 break;
831 case SQR_STYPE:
832 Fractal->Iteration_Method = Iteration_Julia;
833 Fractal->D_Iteration_Method = D_Iteration_Julia;
834 Fractal->Normal_Calc_Method = Normal_Calc_Julia;
835 break;
836 default:
837 Error("illegal function: quaternion only supports sqr and cube");
839 Fractal->F_Bound_Method = F_Bound_Julia;
841 break;
843 case HYPERCOMPLEX_TYPE:
845 switch (Fractal->Sub_Type)
847 case RECIPROCAL_STYPE:
849 Fractal->Iteration_Method = Iteration_HCompl_Reciprocal;
850 Fractal->Normal_Calc_Method = Normal_Calc_HCompl_Reciprocal;
851 Fractal->D_Iteration_Method = D_Iteration_HCompl_Reciprocal;
852 Fractal->F_Bound_Method = F_Bound_HCompl_Reciprocal;
854 break;
856 case EXP_STYPE:
857 case LOG_STYPE:
858 case SIN_STYPE:
859 case ASIN_STYPE:
860 case COS_STYPE:
861 case ACOS_STYPE:
862 case TAN_STYPE:
863 case ATAN_STYPE:
864 case SINH_STYPE:
865 case ASINH_STYPE:
866 case COSH_STYPE:
867 case ACOSH_STYPE:
868 case TANH_STYPE:
869 case ATANH_STYPE:
870 case PWR_STYPE:
872 Fractal->Iteration_Method = Iteration_HCompl_Func;
873 Fractal->Normal_Calc_Method = Normal_Calc_HCompl_Func;
874 Fractal->D_Iteration_Method = D_Iteration_HCompl_Func;
875 Fractal->F_Bound_Method = F_Bound_HCompl_Func;
876 Fractal->Complex_Function_Method = Complex_Function_List[Fractal->Sub_Type];
878 break;
880 case CUBE_STYPE:
882 Fractal->Iteration_Method = Iteration_HCompl_z3;
883 Fractal->Normal_Calc_Method = Normal_Calc_HCompl_z3;
884 Fractal->D_Iteration_Method = D_Iteration_HCompl_z3;
885 Fractal->F_Bound_Method = F_Bound_HCompl_z3;
887 break;
889 default: /* SQR_STYPE or else... */
891 Fractal->Iteration_Method = Iteration_HCompl;
892 Fractal->Normal_Calc_Method = Normal_Calc_HCompl;
893 Fractal->D_Iteration_Method = D_Iteration_HCompl;
894 Fractal->F_Bound_Method = F_Bound_HCompl;
896 break;
899 break;
901 default:
903 Error("Algebra unknown in fractal.");
906 Allocate_Iteration_Stack(Fractal->n);
908 Compute_Fractal_BBox(Fractal);
911 /*****************************************************************************
913 * FUNCTION
915 * INPUT
917 * OUTPUT
919 * RETURNS
921 * AUTHOR
923 * Pascal Massimino
925 * DESCRIPTION
929 * CHANGES
931 * Dec 1994 : Creation.
933 ******************************************************************************/
935 void Allocate_Iteration_Stack(int n)
937 if (n > Allocated_Iteration_Stack_Length)
939 Sx = (DBL *) POV_REALLOC(Sx, (n + 1) * sizeof(DBL), "x iteration stack");
940 Sy = (DBL *) POV_REALLOC(Sy, (n + 1) * sizeof(DBL), "y iteration stack");
941 Sz = (DBL *) POV_REALLOC(Sz, (n + 1) * sizeof(DBL), "w iteration stack");
942 Sw = (DBL *) POV_REALLOC(Sw, (n + 1) * sizeof(DBL), "z iteration stack");
944 Allocated_Iteration_Stack_Length = n;
948 /*****************************************************************************
950 * FUNCTION
952 * INPUT
954 * OUTPUT
956 * RETURNS
958 * AUTHOR
960 * Pascal Massimino
962 * DESCRIPTION
966 * CHANGES
968 * Dec 1994 : Creation.
970 ******************************************************************************/
972 void Free_Iteration_Stack()
974 if (Sx != NULL)
976 POV_FREE(Sx);
977 POV_FREE(Sy);
978 POV_FREE(Sz);
979 POV_FREE(Sw);
982 Sx = NULL;
983 Sy = NULL;
984 Sz = NULL;
985 Sw = NULL;
987 Allocated_Iteration_Stack_Length = 0;