/**
 * Mandelbulber v2, a 3D fractal generator  _%}}i*<.        ____                _______
 * Copyright (C) 2021 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%+++
 *
 * KochV3 Baird Delta
 * formula coded by Knighty in fragmentarium:
 * based on formula by Eric Baird
 * https://www.researchgate.net/publication/262600735_The_Koch_curve_in_three_dimensions

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

REAL4 KochV3Iteration(REAL4 z, __constant sFractalCl *fractal, sExtendedAuxCl *aux)
{
	REAL beta = fractal->transformCommon.angle72 * M_PI_F / 360.0f;
	REAL tc = tan(beta);
	REAL tsq = native_sqrt(3.0f * tc * tc - 1.0f) * 0.25f;

	REAL4 fl1 = ((REAL4){1.0f, 0.0f, -2.0f * tsq, 0.0f});
	fl1 = fl1 / native_sqrt(1.0f + 4.0f * tsq * tsq);
	tc = native_cos(beta);

	REAL BDscale = fractal->transformCommon.scale4 * tc * tc;

	// Sierpinski triangle symmetry + fold about xy, plane plus folds inserted
	if (fractal->transformCommon.functionEnabledAxFalse) z.x = fabs(z.x);
	if (fractal->transformCommon.functionEnabledAy) z.y = fabs(z.y);
	if (fractal->transformCommon.functionEnabledAz) z.z = fabs(z.z);

	// folds
	if (fractal->transformCommon.functionEnabledFalse)
	{
		// diagonal
		if (fractal->transformCommon.functionEnabledCxFalse)
			if (z.y > z.x)
			{
				REAL temp = z.x;
				z.x = z.y;
				z.y = temp;
			}
		// polyfold
		if (fractal->transformCommon.functionEnabledPFalse)
		{
			z.x = fabs(z.x);
			REAL psi = M_PI_F / fractal->transformCommon.int6;
			psi = fabs(fmod(atan2(z.y, z.x) + psi, 2.0f * psi) - psi);
			REAL len = native_sqrt(z.x * z.x + z.y * z.y);
			z.x = native_cos(psi) * len;
			z.y = native_sin(psi) * len;
		}
		// abs offsets
		if (fractal->transformCommon.functionEnabledCFalse)
		{
			REAL xOffset = fractal->transformCommon.offsetC0;
			if (z.x < xOffset) z.x = fabs(z.x + xOffset) - xOffset;
		}
	}

	// REAL Pid6 = M_PI_F / 6.0f;
	REAL CPid6 = SQRT_3_4_F; // cos(Pi / 6);
	REAL SPid6 = -0.5f;			 // native_sin(Pi / 6);
	REAL t = 2.0f * min(0.0f, z.x * CPid6 + z.y * SPid6);
	z.x -= t * CPid6;
	z.y -= t * SPid6;
	z.y = fabs(z.y);

	// Koch curve fold
	z.x -= 0.5f;
	z.z -= tsq;
	t = 2.0f * min(0.0f, dot(z, fl1));
	z -= t * fl1;
	z.x += 0.5f;
	z.z += tsq;
	z.x -= 1.0f;

	// rotation
	if (fractal->transformCommon.functionEnabledRFalse
			&& aux->i >= fractal->transformCommon.startIterationsR
			&& aux->i < fractal->transformCommon.stopIterationsR)
	{
		z = Matrix33MulFloat4(fractal->transformCommon.rotationMatrix, z);
	}

	// scale
	z *= BDscale;
	aux->DE *= BDscale;
	z.x += 1.0f;

	aux->dist = (length(z) - 3.0f) / aux->DE;
	return z;
}