vex_functions

float preview (int preview_toggle; float value_preview, value_final)
{

    if (preview_toggle)
    {
        return value_preview;
    }else{
        return value_final;
    }
}

int preview (int preview_toggle; int value_preview, value_final)
{

    if (preview_toggle)
    {
        return value_preview;
    }else{
        return value_final;
    }
}


void clamp01(float value)
{
    value = clamp(value,0,1);    
}


string ftoa(float value)
{
    return sprintf("%g", value);
}


string padzero(int size, value)
{
        string format = '%0' + itoa(size) + 'd';
        string eval   = sprintf(format, value) ;
        return eval;
}



float blend( float array[]; float index )
{

    float value_0 , value_1;
    float index_01;
    float eval;

    value_0  = array [floor(       index   )];
    value_1  = array [floor(  ceil(index)  )];
    index_01 = index % 1;

    eval = fit01(index_01, value_0, value_1);

    return eval;
}



float dim_falloff_linear(vector pos, from, to)
{
    vector u = normalize(to - from);
    vector v = pos - from;

    float eval = dot(u,v) / length(to - from);
    return eval;
}


float dim_falloff_radial(vector pos, center, extent)
{
    float max  = length(extent - center);
    float eval = length(pos - center) / max;
    return eval;
}



void dim_segment(int geometry; string class, name)
{

    int count;
    float eval;
    if (class == "point")
        count = npoints(0);

    if (class == "prim")
        count = nprimitives(0);
    
    eval = 0;

    for (int elem = 0; elem < count; elem++)
    {
        setdetailattrib(0,name,eval);
    }

}


void distort_bias(float dimension, bias) 
{
    if (dimension <= 0)
        dimension = 0;
    else if (dimension >= 1)
        dimension = 1;
    else
        dimension = (1-bias) / (((1.0 / dimension) - 2) * (bias) + 1);
}

float distort_bias(float dimension, bias) 
{
    float eval;
    if (dimension <= 0)
        eval = 0;
    else if (dimension >= 1)
        eval = 1;
    else
        eval = (1-bias) / (((1.0 / dimension) - 2) * (bias) + 1);
    return eval;
}


void distort_ease(float dimension, ease) 
{
    if(dimension<0.5)
        dimension = distort_bias(dimension*2,ease)/2;
    else
        dimension = 1 - distort_bias((1-dimension)*2,ease)/2;
}



void distort_noise(float dimension, noise, limit_impact; string channel)
{
    float impact = chramp(channel, dimension);

    if (limit_impact)
    {
        // triangle
        float limit_from_top = 1 - dimension;
        float limit_from_bot =     dimension;
        impact *= min(limit_from_top, limit_from_bot);
    } 

    dimension = dimension + impact * noise;
}



void distort_lut(float dimension; string channel)
{
    dimension = chramp(channel, dimension);
}



void distort_shrink(float dimension, from_zero, from_one) 
{
    dimension = fit(dimension, from_zero, from_one, 0, 1);
}



void distort_segment(float dimension; int segment, segment_max; float offset_0, offset_1; int enable_gaps)
{

    float segment_rel = float (segment) / float(segment_max);
    float off_0, off_1;

    if (enable_gaps)
    {
        off_0 = min(offset_0,0.99999);
        off_1 = max(offset_1,0.00001);
    } 
    else
    {
        // correct offset to not overlap
        off_0 = fit01( offset_0,         0         ,  1-1/float(segment_max+1) );
        off_1 = fit01( offset_1, 1/float(segment_max+1) ,            1         );
    }

    float wide_min = segment_rel * off_0;
    float wide_max = 1-(1-segment_rel) * (1-off_1);

    dimension = fit(dimension, wide_min, wide_max, 0, 1);

}



float coord_midi(string name; float pitch, time)
{
    string geo       = "op:/obj/midi/mixer/" + name;
    float i[]        = detail(geo, name);
    int midi_total_frames = detail(geo, "midi_total_frames");
    int index        = floor(time) + midi_total_frames * floor(pitch);
    
    float result     = i[index];
    return result;
}



float fill_to_coord(float dimension, coord, feather_spread) //clamped
{
    float eval, trywide;
    trywide = fit01(coord, -feather_spread/2 , 1+feather_spread/2);

    if ( feather_spread>0 )
    {
        float omin = dimension - feather_spread/2;
        float omax = dimension + feather_spread/2;
        eval = fit(trywide, omin, omax, 0, 1);
    } else {
        if ( trywide > dimension )
        {
            eval = 1;
        } else {
            eval = 0;
        }
    }

    if (coord == 1) eval = 1;
    if (coord == 0) eval = 0;

    return eval;
}


float geo_line_u (int geometry, ptnum)
{
    
    int linvert   = pointvertex (geometry, ptnum);
    int vertex    = vertexprimindex (geometry, linvert);
    int primnum[] = pointprims (geometry, ptnum);
    int count     = primvertexcount (geometry, primnum[0]);
    
    float eval    = vertex / float (count-1);

    return eval;
}



void geo_carve_point (int geometry, primnum; float u)
{
    int oldprim = primnum;
    int newprim = addprim(geometry, "polyline");
    vector pos  = primuv(0, "P", primnum, set(u,0,0));
    vector N    = primuv(0, "N", primnum, set(u,0,0));
    vector up   = primuv(0, "up", primnum, set(u,0,0));
    
    int ptnum   = addpoint(newprim, pos);
    int vertex  = addvertex(0, newprim, ptnum);

    setpointattrib(0, "N", ptnum, N, "set");
    setpointattrib(0, "up", ptnum, up, "set");
    
    removeprim  (geometry, oldprim, 1);
}



void geo_carve_line (int geometry, primnum; float start, end)
{

    vector getlinepos(int primnum; float u) {
        vector pos = primuv(0, "P", primnum, set(u,0,0));
        return pos;
    }
    int    createpoint(int primnum; vector pos) {
        int ptnum = addpoint(primnum, pos);
        int vertex = addvertex(0, primnum, ptnum);
        return vertex;
    }

    int oldprim  = primnum;
    int closed   = primintrinsic(geometry, "closed", oldprim);
    int segments = primvertexcount(geometry, oldprim) - 1 + closed;

    //---------------------------
    //---------------------------

    if (start==end){
        //nothing
    }

    //---------------------------
    //---------------------------

    if (start<end){
    
        int newprim = addprim(geometry, "polyline");
        
        //new point at start
        createpoint(newprim, getlinepos(oldprim, start));
                
        //points from prim
        int startvert, endvert;

        startvert  = 1 + floor(start * segments);
        endvert    = 1 + floor(end * segments);
        endvert    = min(endvert, segments);
        
        for (int i = startvert; i < endvert; i++)
        {
            vector vertpos = vertex(geometry, "P", oldprim, i);
            createpoint(newprim, vertpos);
        }

        //new point at end
        createpoint(newprim, getlinepos(oldprim, end));

    } 

    //---------------------------
    //---------------------------


    if (start>end){

        int newprim;
        newprim = addprim(geometry, "polyline");
        
        //from prim
        int startvert, endvert;
        startvert  = 1 + floor(start * segments);
        endvert    = 1 + floor(end * segments);
        endvert    = min(endvert, segments);
        
        for (int i = 0; i < endvert; i++)
        {
            vector vertpos = vertex(geometry, "P", oldprim, i);
            createpoint(newprim, vertpos);
        }
        
        //new point at end
        createpoint(newprim, getlinepos(oldprim, end));
        
        //new point at start
        newprim = addprim(geometry, "polyline");
        createpoint(newprim, getlinepos(oldprim, start));
        
        //from prim
        for (int i = startvert; i <= segments; i++)
        {
            vector vertpos;
            if (i==segments && closed)
            {
                // this is special, on closed: last = firt        
                vertpos = vertex(geometry, "P", oldprim, 0);
            } else {
                // usual point
                vertpos = vertex(geometry, "P", oldprim, i);
            }
            createpoint(newprim, vertpos);
        }
    }

    //---------------------------
    //---------------------------

    removeprim(geometry, oldprim, 1);

}




vector geo_farthest_point_position (int geometry; vector farthest_point_from) //run over detail of input 0
{
    int count = npoints(geometry);
    float maxdist = 0;
    vector eval;

    for (int pt = 0; pt < count; pt++)
    {
        vector sample_pos = point(0,"P",pt);
        float distance = length(sample_pos - farthest_point_from);
        if (distance > maxdist) 
        {
            maxdist = distance;
            eval    = sample_pos;
        }
    }
    return eval;
}


vector geo_farthest_point_distance (int geometry; vector from) //pointcloud of input 0
{
    int maxpts = npoints( geometry);
    int handle = pcopen( geometry, "P", from, radius, maxpts);
    float eval = pcfarthest(handle);
    pcclose(handle);
    return eval;
}




vector geo_closest_point_position(string surface_geo; vector from)
{
    vector uv_found ;
    int prim_found ;
    float distance = xyzdist("op:" + surface_geo, from, prim_found, uv_found);
    vector pos_closest = primuv("op:" + surface_geo, "P", prim_found, uv_found);
    return pos_closest;
}

vector geo_closest_point_position(int surface_geo; vector from)
{
    vector uv_found ;
    int prim_found ;
    float distance = xyzdist(surface_geo, from, prim_found, uv_found);
    vector pos_closest = primuv(surface_geo, "P", prim_found, uv_found);
    return pos_closest;
}



void geo_bounding_vector (int geometry; vector direction_from, direction_to, result_from, result_to)
{
    vector u, v, pos, center;
    float distance, mindist, maxdist;
    int count = npoints(geometry);

    u = normalize(direction_to - direction_from);
    mindist = 1e10;
    maxdist = -1e10;

    for (int pt = 0; pt < count; pt++)
    {   
        pos = point(geometry,"P",pt);
        v = pos - direction_from;
        distance = dot(u,v);

        maxdist = max(distance, maxdist);
        mindist = min(distance, mindist);
    }

    v = getbbox_center(geometry) - direction_from;
    center = dot(u,v);

    result_to = (maxdist - center) * u + getbbox_center(geometry) ;
    result_from = (mindist - center) * u + getbbox_center(geometry) ;
}





vector vec_len_fit01(vector noise; float xmin, xmax, ymin, ymax, zmin, zmax)
{
    vector eval = noise;

    eval[0] = fit01(eval[0], xmin, xmax);
    eval[1] = fit01(eval[1], ymin, ymax);
    eval[2] = fit01(eval[2], zmin, zmax);

    return eval;
}



vector vec_dir_randomize(vector vec; float amount, seed) {

    vector vec_rand;
    float length_orig = length(vec);

    // getting different random value for each axis, scaling to [-1..1] range
    // thanks to Juraj Tomori for this script
    vec_rand.x = rand(seed * 684.49848) * 2 - 1;
    vec_rand.y = rand(seed * 178.46548) * 2 - 1;
    vec_rand.z = rand(seed * 489.49856) * 2 - 1;
    
    vec_rand = lerp(vec, vec_rand, amount);
    vec_rand = normalize(vec_rand) * length_orig;

    return vec_rand;
}


vector vec_dir_quantize(vector orig )
{


    int reference_geo = 1;
    // vec_prim = 0;
    // vec_total = primvertexcount(reference_geo, vec_prim);
    vector quant = {0,0,0};

    int count = 3;

    for (int i = 0; i < count; i++)
    {
        vector quant_dir = normalize(  point(reference_geo,"P",i)  ) ;
        
        float quant_add;
        quant_add = dot (  normalize(orig)  ,  quant_dir  );
        quant_add = rint (quant_add) ;

        quant += quant_add * quant_dir;
    }

    quant = length(orig) * normalize( quant );
    return quant;

}




vector euler_from_quat(vector4 orient)
{
    vector  eval;
    vector4 quaternion = orient;
    matrix m = matrix( qconvert( quaternion ) );
    eval = cracktransform(0, 0, 1, {0,0,0}, m);

    return eval;

}


vector4 quat_from_zy(vector z,y)
{
    vector4 eval;
    matrix3 m = maketransform(z, y);
    eval = quaternion(m);
    return eval;
}


matrix xmat(vector amount, pivot; vector4 orient; string trs)
{
    matrix eval;

    vector t = {0,0,0};
    vector r = {0,0,0};
    vector s = {1,1,1};

    vector pr = euler_from_quat(orient);

    if (trs == "translate")    
        t = amount;
    if (trs == "rotate")       
        r = amount;
    if (trs == "scale")        
        s = amount;

    eval = maketransform(0, 0,  t,  r,  s,  pivot, pr);

    return eval;
}


void intri_xmat(int primnum; matrix xmat)
{
    matrix3 transform = primintrinsic(0, "transform", primnum);
    transform *= matrix3 (xmat);
    setprimintrinsic(0,"transform", primnum, transform);
}



float time_sequence(float current, zero_at, seq_length, speed; string type)
{

    float eval, seq_length_retimed, relative_range;

    seq_length_retimed = seq_length / speed;
    relative_range = (current - zero_at) / seq_length_retimed;

    if (type == "once")
    {
        relative_range = clamp(relative_range, 0, 1);
        eval = relative_range * seq_length;
    }

    if (type == "loop")
    {
        relative_range = relative_range % 1;
        eval = relative_range * seq_length;
    }

    if (type == "ping")
    {
        relative_range = 1 - abs (relative_range % 2 - 1);
        eval = relative_range * seq_length;
    }

    return eval;
}


float time_snap(int frame_current, frame_snap, smooth_frames; float value_at_snap, speed_before, speed_after)

{
    int frame_0 = min(frame_snap,frame_snap + smooth_frames);
    int frame_1 = max(frame_snap,frame_snap + smooth_frames);


    // distance linear after
    int     frames_lin_after  = max(0,  frame_current-frame_1  );
    float distance_lin_after  = frames_lin_after * speed_after;


    // distance linear before
    int     frames_lin_before = min(0,  frame_current-frame_0  );
    float distance_lin_before = frames_lin_before * speed_before;


    // distance smooth
    int range_start = 0;
    int range_end   = 0;
    float sign      = 0;

    if (frame_current > frame_snap && smooth_frames > 0)
    {
        range_start = frame_snap;
        range_end   = min(frame_current, frame_1);
        sign        = 1;
    }

    if (frame_current < frame_snap && smooth_frames < 0)
    {
        range_start = max(frame_current, frame_0);
        range_end   = frame_snap;
        sign        = -1;
    }

    float distance_smooth = 0;

    for (int f_in = range_start; f_in < range_end ; f_in++)
    {
            float speed     = smooth(frame_0, frame_1, f_in);
            speed           = fit01(speed,speed_before,speed_after);
            distance_smooth += sign * speed;
    }

    float distance;

    distance = value_at_snap;
    distance += distance_lin_before;
    distance += distance_lin_after;
    distance += distance_smooth;

    return distance;
}



float time_twosnap(int frame_current, snapframe_0, snapframe_1, frames_smooth_0, frames_smooth_1; float value_0, value_1)

{
    int cur    = frame_current;

    // check for overlaps
    int snap_0 = min(snapframe_0,snapframe_1);
    int snap_1 = max(snapframe_0,snapframe_1);

    int range_total = snap_1 - snap_0;
    int range_lin   = max (0, range_total - frames_smooth_0 + frames_smooth_1);
    int range_0     = max (0, range_total - range_lin   + frames_smooth_1);
    int range_1     = max (0, range_total - range_lin   - range_0);

    // keyframes (range breaks)
    int key_0 = snap_0;
    int key_1 = snap_0 + range_0;
    int key_2 = snap_1 - range_1;
    int key_3 = snap_1;

    // speed
    float speed_normalized = float(range_0)/2 + float(range_1)/2 + float(range_lin);
    float speed_mult       = (value_1 - value_0)  /  speed_normalized;
    float speed;

    float value = value_0;
    

    // distance in range 0
    if(range_0 > 1)
    {
        for (int f_in = key_0; f_in < min(key_1,cur) ; f_in++)
        {
            speed  = speed_mult * smooth(key_0, key_1 - 1, f_in);
            value += speed;
        }
    }

    // distance in range linear
    if(range_lin) 
    {
        for (int f_in = key_1; f_in < min(key_2,cur) ; f_in++)
        {
            speed  = speed_mult;
            value += speed;
        }
    }

    // distance in range 1
    if(range_1 > 1) 
    {
        for (int f_in = key_2; f_in < min(key_3,cur) ; f_in++)
        {
            speed  = speed_mult * (   1 - smooth(key_2, key_3 - 1, f_in)   );
            value += speed;
        }
    }

    return value;
    //return float(range_lin);
}








string file_mov_index(string firstfile; int mov, index)
{

    string split[] = split(firstfile,"/_.");
    int split_len  = len(split);
    //[ D:, bond, "5 houdini", img, dir, name, 000, name, 000, 00000, png ]

    int file_name_len  = len( split[ split_len -4 ] );
    int file_mov_len   = len( split[ split_len -3 ] );
    int file_index_len = len( split[ split_len -2 ] );
    int file_ext_len   = len( split[ split_len -1 ] );

    int afterpath_len  = file_ext_len + 1 + file_index_len + 1 + 2*file_mov_len + 2 + 1 + 2*file_name_len;

    string file_path  = slice(firstfile,0,-afterpath_len);
    string file_name  = split[split_len - 4];
    string file_type  = split[split_len - 1];

    string file_mov   = padzero(file_mov_len, mov);
    string file_index = padzero(file_index_len, index);

    string path;

    path  = file_path;
    path += file_name + "_";
    path += file_mov  + "/";
    path += file_name + "_";
    path += file_mov  + "_";
    path += file_index+ ".";
    path += file_type;

    return path;
}



string file_index(string firstfile; int index)
{

    string split[] = split(firstfile,"/_.");
    int split_len  = len(split);
    //[ D:, bond, "5 houdini", img, "seq timecode", timecode, 00001, jpg ]


    int file_name_len  = len( split[ split_len -3 ] );
    int file_index_len = len( split[ split_len -2 ] );
    int file_ext_len   = len( split[ split_len -1 ] );

    int afterpath_len  = file_ext_len + 1 + file_index_len + 1 + file_name_len;

    string file_path  = slice(firstfile,0,-afterpath_len);
    string file_name  = split[split_len - 3];
    string file_type  = split[split_len - 1];

    string file_index = padzero(file_index_len, index);

    string path;

    path  = file_path;
    path += file_name + "_";
    path += file_index+ ".";
    path += file_type;

    return path;
}



void mat_over(string actual, override_name, override_value; int override_is_string)
{
    string contents, add, value;
    value = override_value;
    contents = slice(actual,1,-1); // remove { }
    if (override_is_string) value = "'" + value + "'";
    add = "'" + override_name + "':" + value;
    actual = "{" + contents + add + ",}";
}


void col_hue(vector color; int seed; float spread)
{

}



vector noise_vref (vector p; string operator)
{
    float px = p[0];
    float py = p[1];
    float pz = p[2];

    float amp   = detail("op:" + operator , "amp" );
    float f     = detail("op:" + operator , "f" );
    float fx    = detail("op:" + operator , "fx" );
    float fy    = detail("op:" + operator , "fy" );
    float fz    = detail("op:" + operator , "fz" );
    float s     = detail("op:" + operator , "s" );
    float sx    = detail("op:" + operator , "sx" );
    float sy    = detail("op:" + operator , "sy" );
    float sz    = detail("op:" + operator , "sz" );
    int turb    = detail("op:" + operator , "turb" );
    float rough = detail("op:" + operator , "rough" );
    float atten = detail("op:" + operator , "atten" );
    float ox    = detail("op:" + operator , "ox" );
    float oy    = detail("op:" + operator , "oy" );
    float oz    = detail("op:" + operator , "oz" );
    float time  = detail("op:" + operator , "time" );

    float x = px * f * fx - ox + s * sx * time;
    float y = py * f * fy - oy + s * sy * time;
    float z = pz * f * fz - oz + s * sz * time;

    vector pos = set(x,y,z);
    vector noise;

    noise = onoise(pos, turb, rough, atten);
    noise = noise * amp;

    noise[0] = smooth(-1,1,noise[0]);
    noise[1] = smooth(-1,1,noise[1]);
    noise[2] = smooth(-1,1,noise[2]);

    return noise;

}


vector noise_vstat (float px, py, pz , f, fx, fy, fz, ox, oy, oz; int turb; float rough, atten, amp )
{

    float x = px * f * fx - ox;
    float y = py * f * fy - oy;
    float z = pz * f * fz - oz;

    vector pos = set(x,y,z);
    vector noise;

    noise = onoise(pos, turb, rough, atten);
    noise = noise * amp;

    noise[0] = smooth(-1,1,noise[0]);
    noise[1] = smooth(-1,1,noise[1]);
    noise[2] = smooth(-1,1,noise[2]);

    return noise;

}



vector noise_vanim (float px, py, pz , f, fx, fy, fz, s, sx, sy, sz, ox, oy, oz, time; int turb; float rough, atten, amp )
{

    float x = px * f * fx - ox + s * sx * time;
    float y = py * f * fy - oy + s * sy * time;
    float z = pz * f * fz - oz + s * sz * time;

    vector pos = set(x,y,z);
    vector noise;

    noise = onoise(pos, turb, rough, atten);
    noise = noise * amp;

    noise[0] = smooth(-1,1,noise[0]);
    noise[1] = smooth(-1,1,noise[1]);
    noise[2] = smooth(-1,1,noise[2]);

    return noise;

}


float noise_fstat ( float pos, f, offset, turb, rough, atten, amp )
{

    float sample = pos * f - offset;
    float noise;

    noise = onoise(sample, turb, rough, atten);
    noise = noise * amp;

    noise = smooth(-1,1,noise);

    return noise;

}


float noise_fanim ( float px, py, f, sx, sy, ox, oy, time; int turb; float rough, atten, amp )
{

    float x = px * f - ox + sx * time;
    float y = py * f - oy + sy * time;
    float z = 12.3456789;

    vector pos = set(x,y,z);
    vector noise;

    noise = onoise(pos, turb, rough, atten);
    noise = noise * amp;

    float noise_x = getcomp(noise, 0);
    noise_x = smooth(-1,1,noise_x);

    return noise_x;

}