#include <amscudafractallevelset/amscudafractallevelset.cuh>

namespace amscuda
{
namespace fractallevelset
{


// __host__ __device__ float main_function(cuvec3f pos, main_functionpars &pars)
// {
//     float ret = 0.0f;

//     ret = pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]-pars.threshold;

//     return -ret;
// };

#ifdef AMSCLS_MANDELBROT
__host__ __device__ float main_function(cuvec3f pos, main_functionpars &pars)
{
    float ret = 0.0f;
    float wr,wtheta,wphi;
    cuvec3f w,c;
    int I;

    w = pos;
    if(pars.isjulia) 
        c = pars.juliac;
    else
        c = pos;

    for(I=0;I<pars.fractaliter;I++)
    {
        wr = cuvec3f_norm(w);
        wtheta = ::acos(w.y/wr);
        wphi = ::atan2(w.x,w.z);
        if(wr>pars.freezethresh) break;
        wr = ::pow(wr,pars.exponent);
        wtheta = wtheta*pars.exponent;
        wphi = wphi*pars.exponent;
        w = cuvec3f(wr*sin(wtheta)*sin(wphi),wr*cos(wtheta),wr*sin(wtheta)*cos(wphi));
        w = w + c;
    }

    ret = cuvec3f_norm(w)-pars.threshold;

    return ret;
};
#endif


#ifdef AMSCLS_PPKFRACTAL
__host__ __device__ float main_function(cuvec3f pos, main_functionpars &pars)
{
    float ret = 1E6;
    cuvec3f z;
    float offset;
    cuvec3f c;
    float dr = 1.0f;
    float signfactor;
    int I;

    if(pars.isjulia)
    {
        c = pars.juliac;
        offset = 0.0;
    }
    else
    {
        c = pos;
        offset = 1.0;
    }
    signfactor = (pars.scale<0.0f)? 0.95f : 1.0f;

    z = pos;

    for(I=0;I<pars.fractaliter;I++)
    {
        if(::fabs(z.y)>8.0f)
        {
            break;
        }

        float sx,cx,sz,cz,shy,chy;
        sx = sinf(z.x);
        cx = cosf(z.x);
        sz = sinf(z.z);
        cz = cosf(z.z);
        shy = sinhf(z.y);
        chy = coshf(z.y);

        z = cuvec3f(sx*chy,cx*cz*shy,sz*chy)*pars.scale + c;
        float stretch = 0.75f*::sqrtf(chy*chy + shy*shy);
        if(stretch>0.9f) stretch = 0.9f;
        dr = ::fabs(pars.scale)*signfactor*stretch*dr + offset;
        float q = 1.0f/dr;
        if(q<ret) ret = q;
    }

    return ret;
};

/*
float DE(vec3 pos) {
    vec3 z = pos;
    vec3 juliaC = Julia ? JuliaC : pos;
    float offset = Julia ? 0.0 : 1.0;
    float dr = 1.0;  
    // negative scale swaps sign each iteration, which affects the dr growth
    float signFactor = Scale < 0.0 ? 0.95 : 1.0; 
    float de = 1e20;

    for (int i = 0; i < Iterations; i++) {
        // just for stability, not a real escape condition
        if (abs(z.y) > 8.) break; 

        float sx = sin(z.x), cx = cos(z.x);
        float sz = sin(z.z), cz = cos(z.z);
        // shy and chy can be replaced with taylor approximations to save cycles
        float shy = sinh(z.y), chy = cosh(z.y);
        
        z = vec3(sx * chy, cx * cz * shy, sz * chy) * Scale + juliaC; 

        // 0.75 and 0.9 are magic constants
        float stretch = 0.75 * sqrt(chy * chy + shy * shy);
        stretch = max(0.9, stretch);
        
        dr = abs(Scale) * signFactor * stretch * dr + offset;
        de = min(de, 1.0 / dr);
    }
    return DEMultiplier* de;  
}
*/
#endif
    
};//end namespace fractallevelset
};// end namespace amscuda
