1 /* === S Y N F I G ========================================================= */
2 /*!	\file julia.cpp
3 **	\brief Implementation of the "Julia Set" layer
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **	Copyright (c) 2007 Chris Moore
10 **
11 **	This package is free software; you can redistribute it and/or
12 **	modify it under the terms of the GNU General Public License as
13 **	published by the Free Software Foundation; either version 2 of
14 **	the License, or (at your option) any later version.
15 **
16 **	This package is distributed in the hope that it will be useful,
17 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **	General Public License for more details.
20 **	\endlegal
21 **
22 ** === N O T E S ===========================================================
23 **
24 ** ========================================================================= */
25 
26 /* === H E A D E R S ======================================================= */
27 
28 #ifdef USING_PCH
29 #	include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #	include <config.h>
33 #endif
34 
35 #include "julia.h"
36 
37 #include <synfig/localization.h>
38 #include <synfig/general.h>
39 
40 #include <synfig/string.h>
41 #include <synfig/time.h>
42 #include <synfig/context.h>
43 #include <synfig/paramdesc.h>
44 #include <synfig/renddesc.h>
45 #include <synfig/surface.h>
46 #include <synfig/value.h>
47 #include <synfig/valuenode.h>
48 
49 #endif
50 
51 using namespace std;
52 using namespace etl;
53 using namespace synfig;
54 using namespace modules;
55 using namespace lyr_std;
56 
57 /* === M A C R O S ========================================================= */
58 
59 #define LOG_OF_2		0.69314718055994528623
60 
61 /* === G L O B A L S ======================================================= */
62 
63 SYNFIG_LAYER_INIT(Julia);
64 SYNFIG_LAYER_SET_NAME(Julia,"julia");
65 SYNFIG_LAYER_SET_LOCAL_NAME(Julia,N_("Julia Set"));
66 SYNFIG_LAYER_SET_CATEGORY(Julia,N_("Fractals"));
67 SYNFIG_LAYER_SET_VERSION(Julia,"0.1");
68 SYNFIG_LAYER_SET_CVS_ID(Julia,"$Id$");
69 
70 /* === P R O C E D U R E S ================================================= */
71 
72 inline void
color_neg_flip(Color & color)73 color_neg_flip(Color &color)
74 {
75 	if(color.get_a()==0)
76 	{
77 		color=Color::alpha();
78 		return;
79 	}
80 
81 	if(color.get_a()<0)
82 		color=-color;
83 
84 	if(color.get_r()<0)
85 	{
86 		color.set_g(color.get_g()-color.get_r());
87 		color.set_b(color.get_b()-color.get_r());
88 		color.set_r(0);
89 	}
90 	if(color.get_g()<0)
91 	{
92 		color.set_r(color.get_r()-color.get_g());
93 		color.set_b(color.get_b()-color.get_g());
94 		color.set_g(0);
95 	}
96 	if(color.get_b()<0)
97 	{
98 		color.set_r(color.get_r()-color.get_b());
99 		color.set_g(color.get_g()-color.get_b());
100 		color.set_b(0);
101 	}
102 }
103 
104 /* === M E T H O D S ======================================================= */
105 
Julia()106 Julia::Julia():
107 param_color_shift(ValueBase(Angle::deg(0)))
108 {
109 	param_icolor=ValueBase(Color::black());
110 	param_ocolor=ValueBase(Color::black());
111 	param_iterations=ValueBase(int(32));
112 	param_color_shift=ValueBase(Angle::deg(0));
113 
114 	param_distort_inside=ValueBase(true);
115 	param_distort_outside=ValueBase(true);
116 	param_shade_inside=ValueBase(true);
117 	param_shade_outside=ValueBase(true);
118 	param_solid_inside=ValueBase(false);
119 	param_solid_outside=ValueBase(false);
120 	param_invert_inside=ValueBase(false);
121 	param_invert_outside=ValueBase(false);
122 	param_color_inside=ValueBase(true);
123 	param_color_outside=ValueBase(false);
124 	param_color_cycle=ValueBase(false);
125 	param_smooth_outside=ValueBase(true);
126 	param_broken=ValueBase(false);
127 	param_seed=ValueBase(Point(0,0));
128 
129 	param_bailout=ValueBase(Real(4));
130 	lp=log(log(param_bailout.get(Real())));
131 
132 	SET_INTERPOLATION_DEFAULTS();
133 	SET_STATIC_DEFAULTS();
134 }
135 
136 bool
set_param(const String & param,const ValueBase & value)137 Julia::set_param(const String & param, const ValueBase &value)
138 {
139 
140 	IMPORT_VALUE(param_icolor);
141 	IMPORT_VALUE(param_ocolor);
142 	IMPORT_VALUE(param_color_shift);
143 	IMPORT_VALUE(param_seed);
144 
145 	IMPORT_VALUE(param_distort_inside);
146 	IMPORT_VALUE(param_distort_outside);
147 	IMPORT_VALUE(param_shade_inside);
148 	IMPORT_VALUE(param_shade_outside);
149 	IMPORT_VALUE(param_solid_inside);
150 	IMPORT_VALUE(param_solid_outside);
151 	IMPORT_VALUE(param_invert_inside);
152 	IMPORT_VALUE(param_invert_outside);
153 	IMPORT_VALUE(param_color_inside);
154 	IMPORT_VALUE(param_color_outside);
155 
156 	IMPORT_VALUE(param_color_cycle);
157 	IMPORT_VALUE(param_smooth_outside);
158 	IMPORT_VALUE(param_broken);
159 
160 	IMPORT_VALUE_PLUS(param_iterations,
161 	{
162 		int iterations=param_iterations.get(int());
163 		iterations=value.get(iterations);
164 		if(iterations<0)
165 			iterations=0;
166 		if(iterations>500000)
167 			iterations=500000;
168 		param_iterations.set(iterations);
169 		return true;
170 	}
171 	);
172 	IMPORT_VALUE_PLUS(param_bailout,
173 	{
174 		Real bailout=param_bailout.get(Real());
175 		bailout=value.get(bailout);
176 		bailout*=bailout;
177 		lp=log(log(bailout));
178 		param_bailout.set(bailout);
179 		return true;
180 	}
181 	);
182 
183 	return false;
184 }
185 
186 ValueBase
get_param(const String & param) const187 Julia::get_param(const String & param)const
188 {
189 	EXPORT_VALUE(param_icolor);
190 	EXPORT_VALUE(param_ocolor);
191 	EXPORT_VALUE(param_color_shift);
192 	EXPORT_VALUE(param_iterations);
193 	EXPORT_VALUE(param_seed);
194 
195 	EXPORT_VALUE(param_distort_inside);
196 	EXPORT_VALUE(param_distort_outside);
197 	EXPORT_VALUE(param_shade_inside);
198 	EXPORT_VALUE(param_shade_outside);
199 	EXPORT_VALUE(param_solid_inside);
200 	EXPORT_VALUE(param_solid_outside);
201 	EXPORT_VALUE(param_invert_inside);
202 	EXPORT_VALUE(param_invert_outside);
203 	EXPORT_VALUE(param_color_inside);
204 	EXPORT_VALUE(param_color_outside);
205 	EXPORT_VALUE(param_color_cycle);
206 	EXPORT_VALUE(param_smooth_outside);
207 	EXPORT_VALUE(param_broken);
208 
209 	if(param=="bailout")
210 	{
211 		// This line is needed to copy the static and interpolation options
212 		ValueBase ret(param_bailout);
213 		ret.set(sqrt(param_bailout.get(Real())));
214 		return ret;
215 	}
216 
217 	EXPORT_NAME();
218 	EXPORT_VERSION();
219 
220 	return ValueBase();
221 }
222 
223 RendDesc
get_sub_renddesc_vfunc(const RendDesc & renddesc) const224 Julia::get_sub_renddesc_vfunc(const RendDesc &renddesc) const
225 {
226 	RendDesc desc(renddesc);
227 	desc.set_wh(512, 512);
228 	desc.set_tl(Vector(-5.0, -5.0));
229 	desc.set_br(Vector( 5.0,  5.0));
230 	return desc;
231 }
232 
233 Color
get_color(Context context,const Point & pos) const234 Julia::get_color(Context context, const Point &pos)const
235 {
236 	Color icolor=param_icolor.get(Color());
237 	Color ocolor=param_ocolor.get(Color());
238 	Angle color_shift=param_color_shift.get(Angle());
239 	int iterations=param_iterations.get(int());
240 	Point seed=param_seed.get(Point());
241 	bool distort_inside=param_distort_inside.get(bool());
242 	bool shade_inside=param_shade_inside.get(bool());
243 	bool solid_inside=param_solid_inside.get(bool());
244 	bool invert_inside=param_invert_inside.get(bool());
245 	bool color_inside=param_color_inside.get(bool());
246 	bool distort_outside=param_distort_outside.get(bool());
247 	bool shade_outside=param_shade_outside.get(bool());
248 	bool solid_outside=param_solid_outside.get(bool());
249 	bool invert_outside=param_invert_outside.get(bool());
250 	bool color_outside=param_color_outside.get(bool());
251 
252 	bool color_cycle=param_color_cycle.get(bool());
253 	bool smooth_outside=param_smooth_outside.get(bool());
254 	bool broken=param_broken.get(bool());
255 
256 	Real
257 		cr, ci,
258 		zr, zi,
259 		zr_hold;
260 
261 	ColorReal
262 		depth, mag(0);
263 
264 	Color
265 		ret;
266 
267 	cr=seed[0];
268 	ci=seed[1];
269 	zr=pos[0];
270 	zi=pos[1];
271 
272 	for(int i=0;i<iterations;i++)
273 	{
274 		// Perform complex multiplication
275 		zr_hold=zr;
276 		zr=zr*zr-zi*zi + cr;
277 		zi=zr_hold*zi*2 + ci;
278 
279 		// Use "broken" algorithm, if requested (looks weird)
280 		if(broken)zr+=zi;
281 
282 		// Calculate Magnitude
283 		mag=zr*zr+zi*zi;
284 
285 		if(mag>4)
286 		{
287 			if(smooth_outside)
288 			{
289 				// Darco's original mandelbrot smoothing algo
290 				// depth=((Point::value_type)i+(2.0-sqrt(mag))/PI);
291 
292 				// Linas Vepstas algo (Better than darco's)
293 				// See (http://linas.org/art-gallery/escape/smooth.html)
294 				depth= (ColorReal)i - log(log(sqrt(mag))) / LOG_OF_2;
295 
296 				// Clamp
297 				if(depth<0) depth=0;
298 			}
299 			else
300 				depth=static_cast<ColorReal>(i);
301 
302 			if(solid_outside)
303 				ret=ocolor;
304 			else
305 				if(distort_outside)
306 					ret=context.get_color(Point(zr,zi));
307 				else
308 					ret=context.get_color(pos);
309 
310 			if(invert_outside)
311 				ret=~ret;
312 
313 			if(color_outside)
314 				ret=ret.set_uv(zr,zi).clamped_negative();
315 
316 			if(color_cycle)
317 				ret=ret.rotate_uv(color_shift.operator*(depth)).clamped_negative();
318 
319 			if(shade_outside)
320 			{
321 				ColorReal alpha=depth/static_cast<ColorReal>(iterations);
322 				ret=(ocolor-ret)*alpha+ret;
323 			}
324 			return ret;
325 		}
326 	}
327 
328 	if(solid_inside)
329 		ret=icolor;
330 	else
331 		if(distort_inside)
332 			ret=context.get_color(Point(zr,zi));
333 		else
334 			ret=context.get_color(pos);
335 
336 	if(invert_inside)
337 		ret=~ret;
338 
339 	if(color_inside)
340 		ret=ret.set_uv(zr,zi).clamped_negative();
341 
342 	if(shade_inside)
343 		ret=(icolor-ret)*mag+ret;
344 
345 	return ret;
346 }
347 
348 Layer::Vocab
get_param_vocab() const349 Julia::get_param_vocab()const
350 {
351 	Layer::Vocab ret;
352 
353 	ret.push_back(ParamDesc("icolor")
354 		.set_local_name(_("Inside Color"))
355 		.set_description(_("Color of the Set"))
356 	);
357 	ret.push_back(ParamDesc("ocolor")
358 		.set_local_name(_("Outside Color"))
359 		.set_description(_("Color outside the Set"))
360 	);
361 	ret.push_back(ParamDesc("color_shift")
362 		.set_local_name(_("Color Shift"))
363 	);
364 	ret.push_back(ParamDesc("iterations")
365 		.set_local_name(_("Iterations"))
366 	);
367 	ret.push_back(ParamDesc("seed")
368 		.set_local_name(_("Seed Point"))
369 	);
370 	ret.push_back(ParamDesc("bailout")
371 		.set_local_name(_("Bailout ValueBase"))
372 	);
373 
374 	ret.push_back(ParamDesc("distort_inside")
375 		.set_local_name(_("Distort Inside"))
376 	);
377 	ret.push_back(ParamDesc("shade_inside")
378 		.set_local_name(_("Shade Inside"))
379 	);
380 	ret.push_back(ParamDesc("solid_inside")
381 		.set_local_name(_("Solid Inside"))
382 	);
383 	ret.push_back(ParamDesc("invert_inside")
384 		.set_local_name(_("Invert Inside"))
385 	);
386 	ret.push_back(ParamDesc("color_inside")
387 		.set_local_name(_("Color Inside"))
388 	);
389 	ret.push_back(ParamDesc("distort_outside")
390 		.set_local_name(_("Distort Outside"))
391 	);
392 	ret.push_back(ParamDesc("shade_outside")
393 		.set_local_name(_("Shade Outside"))
394 	);
395 	ret.push_back(ParamDesc("solid_outside")
396 		.set_local_name(_("Solid Outside"))
397 	);
398 	ret.push_back(ParamDesc("invert_outside")
399 		.set_local_name(_("Invert Outside"))
400 	);
401 	ret.push_back(ParamDesc("color_outside")
402 		.set_local_name(_("Color Outside"))
403 	);
404 
405 	ret.push_back(ParamDesc("color_cycle")
406 		.set_local_name(_("Color Cycle"))
407 	);
408 	ret.push_back(ParamDesc("smooth_outside")
409 		.set_local_name(_("Smooth Outside"))
410 		.set_description(_("Smooth the coloration outside the set"))
411 	);
412 	ret.push_back(ParamDesc("broken")
413 		.set_local_name(_("Break Set"))
414 		.set_description(_("Modify equation to achieve interesting results"))
415 	);
416 
417 
418 	return ret;
419 }
420