Very Smooth Multi-Prim Animator

Written by: Headmaster

This was written by Nikkesa:

integer timer_on = 0;

list newPositions; //the list of positions to apply to the segments
list newRotations; //the list of rotations to apply to the segments

float curve_location_x = 360; //the position we are on the curve... 

float distance_between_segments = 0.1; //the distance between each segment

vector segment_size = <0.01,0.1,0.1>;
//let's start setting this **bleep**...
//Note: may want to incorporate support for different types of segments, such as if we had 3 different cones per segment...

integer number_of_segments;

list command_list;

integer i;

float counter = 0;
//setup
vector position_offset;
//part 1
float myAngle1; //the new angle thingy... used later
//part 3
rotation rotation_between; //the rotation between two segments...
vector childPos1;
vector childPos2;
vector newValue;

////////////////////////////

list position_cache;
list rotation_cache;

integer toggle_building_setting = 0;

///////////////////////////

vector childPos(integer segment_id){
    return llList2Vector( llGetLinkPrimitiveParams(segment_id, [PRIM_POSITION] ), 0 );
}

rotation childRot(integer segment_id){
    return llList2Rot(llGetLinkPrimitiveParams(segment_id, [PRIM_ROT_LOCAL]), 0);
}

vector childPosLocal(integer segment_id){
    return llList2Vector(llGetLinkPrimitiveParams(segment_id,[PRIM_POSITION]), 0) - llGetPos();
}

vector buildPositionOffset(rotation rotation_amount, vector current_position, vector axis_position, rotation base_rotation){
    //builds the position offset relative to the rotation_amount relative to the base_rotation (which should be the root prims rotation)
    return ((axis_position - current_position) - ((axis_position - current_position) * rotation_amount)) * base_rotation;
    //this will return the amount we have to move Smiley Very Happy
}

list fix_position_offsets(list myList, float limit_distance){
    //in here we want to basically scale the distance between segments so that it's always the same...
    list newList = myList;
    integer j=1;
    vector segmentPos1;
    vector segmentPos2;
    vector vector_between;
    float distance_between;
    
    for (;j < llGetListLength(myList);j++){
        segmentPos2 = llList2Vector(newList, j);
        segmentPos1 = llList2Vector(newList, j-1);
        vector_between = segmentPos2 - segmentPos1;
        distance_between = llVecMag(vector_between); //get the distance between the segments...
        if (distance_between != limit_distance) {
            //here we scale the distance between the segments
            vector_between = vector_between * (limit_distance / distance_between); //I suspect this is where the math error is coming from.
            //and apply it to the list.
            newList = llListReplaceList(newList, [segmentPos1 + vector_between], j, j);
        }
    }
    return newList;
}

//for a rotation: 
//[((childPos(segment_id) -  llGetPos()) / llGetLocalRot()) + (buildPositionOffset(llEuler2Rot(llRot2Euler(rotation_amount)*segment_id/10), childPos(segment_id), llGetPos() ) * childRot(segment_id))];
//offset_rotaton = llAtan2(llSin(new_curve_mod), new_curve_mod)

integer sign(float input){
    if (input > 0) return 1;
    if (input < 0) return -1;
    return 0;
}

/*
    OKAY, NEW PLAN 
    --------------
    We are going to pre-cache all of the positions and rotations for the animation sequence,
    and apply them over the animation sequence!
    so yeah, whatever. 
    
*/

default
{
    state_entry()
    {
        integer i = 2;
        for (;i<=llGetNumberOfPrims();i++){
            llSetLinkPrimitiveParamsFast(i,[PRIM_POS_LOCAL,<(float)(i-1) * distance_between_segments,0.0,0.0>,PRIM_ROT_LOCAL,ZERO_ROTATION, PRIM_SIZE, segment_size * i/(i+1)]);
        }
        number_of_segments = llGetNumberOfPrims() - 1;
        
        //we want to ignore any avatars,especially in case of attachment and such...
        if (number_of_segments > 1){
            while (llGetAgentSize(llGetLinkKey(number_of_segments))){
                --number_of_segments;
            }
        }
    }
    
    touch_start(integer total_number)
    {
        if (llDetectedKey(0) == llGetOwner()){
            if (timer_on == 0){
                timer_on = 1;
                llSetTimerEvent(0.04);
            } else {
                timer_on = 0;
                llSetTimerEvent(0.0);
                llResetScript();
            }
        }
        
        // let us start the building of the cache.
    }
    
    timer(){
        i = 0;
        counter++;
        
        if (toggle_building_setting == 0)
        {
            curve_location_x = curve_location_x - 12;
            if (curve_location_x <= -1) {
                curve_location_x = 360;
                llOwnerSay("Done Caching... " + (string)counter);
                counter = 0;
                toggle_building_setting = 1;
            }
            command_list = [];
            newPositions = [];
            newRotations = [];
            for (;i < number_of_segments;i++){
                
                //part 1 - set up the new positions for each segment.
                //use i+2
                
                myAngle1 = llSin(( (float)(i+2) * (PI/2 / number_of_segments) )+( curve_location_x*TWO_PI/360 )) * 0.5;
                newValue = (llGetPos() - childPos(i+2));
                //llOwnerSay((string)myAngle1);
                //newPositions += [<(float)(i+2)/(1 / distance_between_segments*0.9),0.0,0.0> + <0.0,llVecMag(newValue) * llSin(myAngle1),0.0>];
                
                newPositions += [<(float)(i+2)/(1 / distance_between_segments),0.0,0.0> + ((newValue) - (newValue * llEuler2Rot( <0.0,0.0,myAngle1> ))) + <0.0,0.0,(llCos((TWO_PI * 3/4) * ((float)1 / (float)26) * (float)i) - 1)/2>];
                
                //newPositions += [<(float)(i+2)/(distance_between_segments),0.0,0.0> + buildPositionOffset(llEuler2Rot( <0.0,myAngle1,myAngle1> ),childPos(i+2), llGetPos(),llGetRot())];
                //newPositions += [<(1/distance_between_segments)*(curve_location_x/360)*i,0.0,0.0>];
                
                //part 3 - set the rotations of the tail segments
                /*
                
                */
                
                //part 4 - build the command list for our setlinkprimparamsfast function
                
                //
                
            }
            newPositions = fix_position_offsets(newPositions, distance_between_segments);
            i = 0;
            for (;i, childPos2 - childPos1);
                newRotations += [rotation_between];
            }
            rotation_cache += newRotations;
            
        } else {
            if (counter == 30){
                counter = 0;
            }
            i = 0;
            command_list = [];
            for (;i