1 /**
2  * Mandelbulber v2, a 3D fractal generator       ,=#MKNmMMKmmßMNWy,
3  *                                             ,B" ]L,,p%%%,,,§;, "K
4  * Copyright (C) 2017-20 Mandelbulber Team     §R-==%w["'~5]m%=L.=~5N
5  *                                        ,=mm=§M ]=4 yJKA"/-Nsaj  "Bw,==,,
6  * This file is part of Mandelbulber.    §R.r= jw",M  Km .mM  FW ",§=ß., ,TN
7  *                                     ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8  * Mandelbulber is free software:     §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9  * you can redistribute it and/or     §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10  * modify it under the terms of the    "§M=M =D=4"N #"%==A%p M§ M6  R' #"=~.4M
11  * GNU General Public License as        §W =, ][T"]C  §  § '§ e===~ U  !§[Z ]N
12  * published by the                    4M",,Jm=,"=e~  §  §  j]]""N  BmM"py=ßM
13  * Free Software Foundation,          ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14  * either version 3 of the License,    TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15  * or (at your option)                   TW=,-#"%=;[  =Q:["V""  ],,M.m == ]N
16  * any later version.                      J§"mr"] ,=,," =="""J]= M"M"]==ß"
17  *                                          §= "=C=4 §"eM "=B:m|4"]#F,§~
18  * Mandelbulber is distributed in            "9w=,,]w em%wJ '"~" ,=,,ß"
19  * the hope that it will be useful,                 . "K=  ,=RMMMßM"""
20  * but WITHOUT ANY WARRANTY;                            .'''
21  * without even the implied warranty
22  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  * See the GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27  *
28  * ###########################################################################
29  *
30  * Authors: Krzysztof Marczak (buddhi1980@gmail.com), Graeme McLaren
31  *
32  * CalculateColorIndex(...) - Calculation of the color index of a point
33  * based on miscellaneous criteria
34  */
35 #include "fractal_coloring.hpp"
36 
37 #include "fractal.h"
38 
39 using std::min;
40 
41 using namespace fractal;
42 
sFractalColoring()43 sFractalColoring::sFractalColoring()
44 {
45 	addEnabledFalse = false;
46 	auxColorFalse = false;
47 	color4dEnabledFalse = false;
48 	colorPreV215False = false;
49 	cosEnabledFalse = false;
50 	extraColorOptionsEnabledFalse = false;
51 	extraColorEnabledFalse = false;
52 	globalPaletteFalse = false;
53 	icFabsFalse = false;
54 	icRadFalse = false;
55 	icXYZFalse = false;
56 	initCondFalse = false;
57 	iterAddScaleTrue = false;
58 	iterGroupFalse = false;
59 	iterScaleFalse = false;
60 	orbitTrapTrue = false;
61 	parabEnabledFalse = false;
62 	radDiv1e13False = false;
63 	radDivDE1e13False = false;
64 	radDivDeFalse = false;
65 	radDivDeSquaredFalse = false;
66 	radFalse = false;
67 	radSquaredFalse = false;
68 	roundEnabledFalse = false;
69 	tempLimitFalse = false; // temporary parameter
70 	xyzBiasEnabledFalse = false;
71 	xyzDiv1e13False = false;
72 	xyzFabsFalse = false;
73 	xyzXSqrdFalse = false;
74 	xyzYSqrdFalse = false;
75 	xyzZSqrdFalse = false;
76 
77 	coloringAlgorithm = fractalColoring_None;
78 	iStartValue = 0;
79 
80 	CVector3 lineDirection;
81 	CVector3 xyz000;
82 	CVector3 xyzC111;
83 
84 	addMax = 0.0;
85 	addSpread = 0.0;
86 	addStartValue = 0.0;
87 	auxColorHybridWeight = 0.0;
88 	auxColorWeight = 0.0;
89 	cosAdd = 0.0;
90 	cosPeriod = 0.0;
91 	cosStartValue = 0.0;
92 	hybridAuxColorScale1 = 0.0;
93 	hybridOrbitTrapScale1 = 0.0;
94 	hybridRadDivDeScale1 = 0.0;
95 	icRadWeight = 0.0;
96 	initialColorValue = 0.0;
97 	iterAddScale = 0.0;
98 	iterScale = 0.0;
99 	maxColorValue = 0.0;
100 	minColorValue = 0.0;
101 	orbitTrapWeight = 0.0;
102 	parabScale = 0.0;
103 	parabStartValue = 0.0;
104 	radDivDeWeight = 0.0;
105 	radDivDeWeight = 0.0;
106 	radWeight = 0.0;
107 	roundScale = 0.0;
108 	sphereRadius = 0.0;
109 	xyzIterScale = 0.0;
110 }
111 
CalculateColorIndex(bool isHybrid,double r,CVector4 z,double colorMin,const sExtendedAux & extendedAux,const sFractalColoring & fractalColoring,fractal::enumColoringFunction coloringFunction,const sFractal * defaultFractal)112 double CalculateColorIndex(bool isHybrid, double r, CVector4 z, double colorMin,
113 	const sExtendedAux &extendedAux, const sFractalColoring &fractalColoring,
114 	fractal::enumColoringFunction coloringFunction, const sFractal *defaultFractal)
115 {
116 	double colorIndex = 0.0;
117 
118 	// color by numbers
119 	if (fractalColoring.extraColorEnabledFalse)
120 	{
121 		double colorValue = 0.0;
122 
123 		// initial color value
124 		colorValue = fractalColoring.initialColorValue;
125 
126 		// colorValue initial condition components
127 		if (fractalColoring.initCondFalse)
128 		{
129 			double initColorValue = 0.0;
130 			CVector3 xyzC = CVector3(extendedAux.c.x, extendedAux.c.y, extendedAux.c.z);
131 			if (fractalColoring.icRadFalse) initColorValue = xyzC.Length() * fractalColoring.icRadWeight;
132 
133 			if (fractalColoring.icXYZFalse)
134 			{
135 				if (fractalColoring.icFabsFalse)
136 				{
137 					xyzC = xyzC * fractalColoring.xyzC111;
138 				}
139 				else
140 				{
141 					xyzC = fabs(xyzC) * fractalColoring.xyzC111;
142 				}
143 				initColorValue += xyzC.x + xyzC.y + xyzC.z;
144 			}
145 			colorValue += initColorValue;
146 		}
147 
148 		// orbit trap component
149 		if (fractalColoring.orbitTrapTrue)
150 		{
151 			// if (fractalColoring.tempLimitFalse) minimumR = min(100.0, minimumR); // TEMP for testing
152 			colorValue += colorMin * fractalColoring.orbitTrapWeight;
153 		}
154 
155 		// auxiliary color components
156 		if (fractalColoring.auxColorFalse)
157 		{
158 			double auxColor = extendedAux.color;
159 			// if (fractalColoring.tempLimitFalse) auxColor = min(auxColor, 1000.0); // TEMP for testing
160 			colorValue += auxColor * fractalColoring.auxColorWeight // aux.color
161 										+ extendedAux.colorHybrid									// transf_hybrid_color inputs
162 												* fractalColoring.auxColorHybridWeight;
163 		}
164 
165 		// radius components (historic)
166 		if (fractalColoring.radFalse)
167 		{
168 			double rad = r;
169 			if (fractalColoring.radDiv1e13False) rad /= 1e13;
170 			if (fractalColoring.radSquaredFalse) rad *= rad;
171 			colorValue += rad * fractalColoring.radWeight;
172 		}
173 
174 		// radius / DE components (historic)
175 		if (fractalColoring.radDivDeFalse)
176 		{
177 			double distEst = extendedAux.DE;
178 
179 			double radDE = r;
180 			if (fractalColoring.radDivDE1e13False) radDE /= 1e13;
181 			if (fractalColoring.radDivDeSquaredFalse) radDE *= radDE;
182 			radDE /= distEst;
183 			// if (fractalColoring.tempLimitFalse) radDE = min(radDE, 20.0); // TEMP for testing
184 
185 			colorValue += radDE * fractalColoring.radDivDeWeight;
186 		}
187 
188 		double addValue = 0.0;
189 		// XYZ bias (example of a basic input)
190 		double xyzValue = 0.0;
191 		if (fractalColoring.xyzBiasEnabledFalse)
192 		{
193 			CVector3 xyzAxis = CVector3(z.x, z.y, z.z);
194 			if (fractalColoring.xyzDiv1e13False) xyzAxis /= 1e13;
195 
196 			if (fractalColoring.xyzFabsFalse)
197 			{
198 				xyzAxis = xyzAxis * fractalColoring.xyz000;
199 			}
200 			else
201 			{
202 				xyzAxis = fabs(xyzAxis) * fractalColoring.xyz000;
203 			}
204 			if (fractalColoring.xyzXSqrdFalse) xyzAxis.x *= xyzAxis.x;
205 			if (fractalColoring.xyzYSqrdFalse) xyzAxis.y *= xyzAxis.y;
206 			if (fractalColoring.xyzZSqrdFalse) xyzAxis.z *= xyzAxis.z;
207 
208 			xyzValue = (xyzAxis.x + xyzAxis.y + xyzAxis.z)
209 								 * (1.0 + (fractalColoring.xyzIterScale * extendedAux.i));
210 		}
211 
212 		addValue += xyzValue; // addValue accumulates outputs
213 
214 		colorValue += addValue; // all extra inputs
215 
216 		// colorValue iteration components
217 		if (fractalColoring.iterGroupFalse)
218 		{
219 			// Iter ADD,  this allows the input to be influenced by iteration number
220 			if (fractalColoring.iterAddScaleTrue && extendedAux.i > fractalColoring.iStartValue)
221 			{
222 				int iUse = extendedAux.i - fractalColoring.iStartValue;
223 				colorValue += fractalColoring.iterAddScale * iUse;
224 			}
225 			// Iter SCALE,
226 			if (fractalColoring.iterScaleFalse && extendedAux.i >= fractalColoring.iStartValue)
227 			{
228 				int iUse = extendedAux.i - fractalColoring.iStartValue;
229 				colorValue *= (iUse * fractalColoring.iterScale) + 1.0;
230 			}
231 		}
232 
233 		// final colorValue controls
234 		if (fractalColoring.globalPaletteFalse)
235 		{
236 			// // add curve function
237 			if (fractalColoring.addEnabledFalse)
238 			{
239 				if (colorValue > fractalColoring.addStartValue)
240 				{
241 					colorValue +=
242 						(1.0
243 							- 1.0
244 									/ (1.0
245 										 + (colorValue - fractalColoring.addStartValue) / fractalColoring.addSpread))
246 						* fractalColoring.addMax;
247 				}
248 			}
249 
250 			// parabolic function
251 			if (fractalColoring.parabEnabledFalse)
252 			{
253 				if (colorValue > fractalColoring.parabStartValue)
254 				{
255 					double parab = colorValue - fractalColoring.cosStartValue;
256 					parab = parab * parab * fractalColoring.parabScale;
257 					colorValue += parab;
258 				}
259 			}
260 
261 			// trig function
262 			if (fractalColoring.cosEnabledFalse)
263 			{
264 				if (colorValue > fractalColoring.cosStartValue)
265 				{
266 					double trig = (0.5
267 													- 0.5
268 															* cos((colorValue - fractalColoring.cosStartValue) * M_PI
269 																		/ (fractalColoring.cosPeriod * 2.0)))
270 												* fractalColoring.cosAdd;
271 					colorValue += trig;
272 				}
273 			}
274 
275 			// round function
276 			if (fractalColoring.roundEnabledFalse)
277 			{
278 				double roundScale = fractalColoring.roundScale;
279 				colorValue /= roundScale;
280 				colorValue = round(colorValue) * roundScale;
281 			}
282 		}
283 
284 		// palette max min controls
285 		double minCV = fractalColoring.minColorValue;
286 		double maxCV = fractalColoring.maxColorValue;
287 		if (colorValue < minCV) colorValue = minCV;
288 		if (colorValue > maxCV) colorValue = maxCV;
289 
290 		colorIndex = colorValue * 256.0; // convert to colorValue units
291 	}
292 
293 	//  HYBRID MODE coloring
294 	else if (isHybrid)
295 	{
296 		// orbit trap
297 		colorMin = min(100.0, colorMin);
298 
299 		// aux.color (init cond = 1.0)
300 		double mboxColor = extendedAux.color;
301 		// double mboxColor = min(extendedAux.color, 1000.0);
302 
303 		// rad/DE
304 		double r2 = min(r / fabs(extendedAux.DE), 20.0);
305 
306 		// summation
307 		if (!fractalColoring.extraColorOptionsEnabledFalse)
308 		{
309 			colorIndex = (colorMin * 1000.0 + mboxColor * 100.0 + r2 * 5000.0);
310 		}
311 		else
312 		{
313 			colorIndex = (colorMin * 1000.0 * fractalColoring.hybridOrbitTrapScale1
314 										+ mboxColor * 100.0 * fractalColoring.hybridAuxColorScale1
315 										+ r2 * 5000.0 * fractalColoring.hybridRadDivDeScale1);
316 		}
317 	}
318 
319 	// NORMAL MODE Coloring (single fractal)
320 	else
321 	{
322 
323 		switch (coloringFunction)
324 		{
325 			case coloringFunctionABox:
326 				colorIndex =
327 					extendedAux.color * 100.0														 // folds part
328 					+ r * defaultFractal->mandelbox.color.factorR / 1e13 // r or abs z part
329 					+ ((fractalColoring.coloringAlgorithm != fractalColoring_Standard) ? colorMin * 1000.0
330 																																						 : 0.0);
331 				// ABOX if fractalColoring_Standard)  minimumR = 0.0
332 				// ABOX r and minimumR values changed in V215 by bailout update
333 				// ABOX extendedAux.color is f(i), change bailout = change value
334 				break;
335 			case coloringFunctionIFS: colorIndex = colorMin * 1000.0; break;
336 			case coloringFunctionAmazingSurf: colorIndex = colorMin * 200.0; break;
337 			case coloringFunctionDonut: colorIndex = extendedAux.color * 2000.0 / extendedAux.i; break;
338 			case coloringFunctionDefault: colorIndex = colorMin * 5000.0; break;
339 			case coloringFunctionUndefined: colorIndex = 0.0; break;
340 		}
341 	}
342 
343 	return colorIndex;
344 }
345