/**
 * Mandelbulber v2, a 3D fractal generator  _%}}i*<.        ____                _______
 * Copyright (C) 2019 Mandelbulber Team   _>]|=||i=i<,     / __ \___  ___ ___  / ___/ /
 *                                        \><||i|=>>%)    / /_/ / _ \/ -_) _ \/ /__/ /__
 * This file is part of Mandelbulber.     )<=i=]=|=i<>    \____/ .__/\__/_//_/\___/____/
 * The project is licensed under GPLv3,   -<>>=|><|||`        /_/
 * see also COPYING file in this folder.    ~+{i%+++
 *
 * Gnarl deformation in 2D (from Mark Townsend), and Luca 2011
 * @reference
 * http://www.fractalforums.com/mandelbulb-3d/custom-formulas-and-transforms-release-t17106/

 * This file has been autogenerated by tools/populateUiInformation.php
 * from the function "TransfGnarlIteration" in the file fractal_formulas.cpp
 * D O    N O T    E D I T    T H I S    F I L E !
 */

REAL4 TransfGnarlIteration(REAL4 z, __constant sFractalCl *fractal, sExtendedAuxCl *aux)
{
	Q_UNUSED(aux);
	REAL4 oldZ = z;
	REAL4 tempZ = z;
	REAL Scale = fractal->transformCommon.scale1;
	REAL stepX = fractal->transformCommon.scale3D000.x; //-0.1;
	REAL stepY = fractal->transformCommon.scale3D000.y;
	REAL stepZ = fractal->transformCommon.scale3D000.z;
	REAL Alpha = fractal->transformCommon.rotation.x; // 2.0f;
	REAL Beta = fractal->transformCommon.rotation.y;	//-4.0;
	REAL Gamma = fractal->transformCommon.rotation.z; //-0.1;

	if (fractal->transformCommon.functionEnabledAx)
	{
		tempZ.x = z.x - stepX * native_sin(z.y + native_sin(Alpha * (z.y + native_sin(Beta * z.y))));
		tempZ.y = z.y - stepY * native_sin(z.x + native_sin(Alpha * (z.x + native_sin(Beta * z.x))));
		z = tempZ;
	}

	if (fractal->transformCommon.functionEnabledAxFalse)
	{
		REAL xx = z.x * z.x;
		tempZ.x = z.x
							+ stepX
									* (native_sin(
										Gamma * (z.y - xx) + native_sin(Alpha * (mad(Beta, native_cos(z.y), z.y)))));
		tempZ.y =
			z.y
			+ stepY
					* (native_sin(Gamma * (z.y + xx) - Alpha * native_sin(mad(Beta, native_cos(xx), xx))));
		z = tempZ;
	}

	if (fractal->transformCommon.functionEnabledAyFalse)
	{
		REAL xx = z.x * z.x;
		REAL yy = z.y * z.y;
		tempZ.y = xx
							+ stepY
									* (native_sin(yy * native_sqrt(fabs(z.y))
																- Alpha * native_sin((yy + native_sin(Beta * yy)))));
		tempZ.x = yy
							- stepX
									* (native_sin(
										xx * native_sqrt(fabs(xx)) + native_sin(Alpha * (xx + native_sin(Beta * xx)))));
		z = tempZ;
	}

	if (fractal->transformCommon.functionEnabledAzFalse)
	{
		tempZ.x = z.x - stepX * native_sin(z.z + native_sin(Alpha * (z.z + native_sin(Beta * z.z))));
		tempZ.y = z.y - stepY * native_sin(z.x + native_sin(Alpha * (z.x + native_sin(Beta * z.x))));
		tempZ.z =
			(z.z - stepZ * native_sin(z.y + native_sin(Alpha * (z.y + native_sin(Beta * z.y))))) * Scale;
		z = tempZ;
	}
	z.x *= Scale;
	z.y *= Scale;

	if (fractal->analyticDE.enabled)
	{
		if (!fractal->analyticDE.enabledFalse)
			aux->DE = mad(aux->DE * fabs(Scale), fractal->analyticDE.scale1, fractal->analyticDE.offset0);
		else
		{
			REAL avgScale = native_divide(length(z), length(oldZ));
			aux->DE = mad(aux->DE * avgScale, fractal->analyticDE.scale1, fractal->analyticDE.offset0);
		}
	}
	return z;
}