Difference between revisions of "Open Prim Animator"

From Second Life Wiki
Jump to navigation Jump to search
m (categorisation)
(not done editiing, yet....still working on it. Improved loop speeds so far and readability of code. Still have to rename variable names to make more sense so we don't need any comments!)
Line 2: Line 2:
// Open Prim Animator - by Todd Borst
// Open Prim Animator - by Todd Borst
// Extensive Modifications by SignpostMarv Martin
// Extensive Modifications by SignpostMarv Martin
 
// This is provided AS IS without support.  Please don't bug me demanding  
// This is provided AS IS without support.  Please don't bug me demanding
// help or custom work for this free script.
// help or custom work for this free script.
 
// Summary: This is a simple prim animation script.  Just add this script
// Summary: This is a simple prim animation script.  Just add this script
// to your object and a dialog will automatically pop up for you to use.
// to your object and a dialog will automatically pop up for you to use.
 
// Features:
// Features:
// -Single script "Prim Puppeteer" like animation tool
// -Single script "Prim Puppeteer" like animation tool
Line 14: Line 14:
// -Animation is scalable and resizeable
// -Animation is scalable and resizeable
// -On-touch trigger built-in
// -On-touch trigger built-in
// -Completely free and open sourced  
// -Completely free and open sourced
 
// License:
// License:
// You are welcome to use this anyway you like, even bring to other grids
// You are welcome to use this anyway you like, even bring to other grids
// outside of Second Life.  If you try to sell what I'm giving away for
// outside of Second Life.  If you try to sell what I'm giving away for
// free, you will be cursed with unimaginably bad juju.
// free, you will be cursed with unimaginably bad juju.
 
integer COMMAND_CHANNEL = 32;
integer COMMAND_CHANNEL = 32;
 
integer primCount = 0;
integer primCount;
integer commandListenerHandle = -1;
integer commandListenerHandle = -1;
 
list posList     = [];
list posList;
list rotList     = [];
list rotList;
list scaleList   = [];
list scaleList;
integer currentSnapshot   = 0;
integer currentSnapshot;
integer recordedSnapshots = 0;
integer recordedSnapshots;
 
vector rootScale   = ZERO_VECTOR;
vector rootScale;
vector scaleChange = <1,1,1>;
vector scaleChange = <1.0, 1.0, 1.0>;
 
// For tracking memory usage.  The amount of snapshots you can record is based
integer maxMemory;
// on the number of prims and available memory.  Less prims = more snapshots
integer freeMemory;
integer maxMemory = 0;
 
integer freeMemory = 0;
// The values for playAnimationStyle means
//     0 :=   no animation playing
integer playAnimationStyle = 0;
//     1 :=   play animation once
// The values for playAnimationStyle means
//     2 :=   play animation looping
// 0 = no animation playing
 
// 1 = play animation once
integer playAnimationStyle;
// 2 = play animation looping
 
   
key op_import = "6b78fcc8-e147-4105-99a6-ff19b4bf559d";
// This function is used to display a recorded snapshot
key op_export = "7c2ca168-2b64-4836-8727-8e62b78dbd44";
showSnapshot(integer snapNumber)
key op_alter_rootScale = "f9d3389e-a78c-43f8-9e35-c11adec112a5";
 
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
 
show_snapshot(integer snapNumber)
{
{
     if(snapNumber > 0 && snapNumber <= recordedSnapshots )
     if (!snapNumber || recordedSnapshots < snapNumber)
        return;
 
    vector rootPos = llGetPos();
    rotation rootRot = llGetRot();
 
    vector pos;
    rotation rot;
    vector scale;
    list params;
 
    integer i = 2;
    do
     {
     {
         integer i = 0;
         pos    = llList2Vector(posList, ((snapNumber - 1)*(primCount - 1)) + (i - 2));
         vector  pos;
         rot     = llList2Rot(rotList, ((snapNumber - 1)*(primCount - 1)) + (i - 2));
        rotation rot;
         scale   = llList2Vector(scaleList, ((snapNumber - 1)*(primCount - 1)) + (i - 2));
         vector   scale;
        vector rootPos = llGetPos();
        // Might want to move llGetRot() into the loop for fast rotating objects.
        // Rotation during the animation playback may cause errors.
        rotation rootRot = llGetRot();


         list params = [];
         if ( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 )
        //2 is the first linked prim number.
        for( i = 2; i <= primCount; i++)
         {
         {
             pos    = llList2Vector(posList,((snapNumber-1)*(primCount-1))+(i-2));
             pos.x *= scaleChange.x;
            rot    = llList2Rot(rotList,((snapNumber-1)*(primCount-1))+(i-2));
            pos.y *= scaleChange.y;
            scale  = llList2Vector(scaleList,((snapNumber-1)*(primCount-1))+(i-2));
            pos.z *= scaleChange.z;
            scale.x *= scaleChange.x;
            //Adjust for scale changes
            scale.y *= scaleChange.y;
            if( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 )
            scale.z *= scaleChange.z;
            {
                pos.x *= scaleChange.x;
                pos.y *= scaleChange.y;
                pos.z *= scaleChange.z;
                scale.x *= scaleChange.x;
                scale.y *= scaleChange.y;
                scale.z *= scaleChange.z;
            }
            params += [
                PRIM_LINK_TARGET,
                    i,
                PRIM_POSITION,
                    pos,
                PRIM_ROTATION,
                    rot/rootRot,
                PRIM_SIZE,
                    scale
            ];
            if(llGetListLength(params) > 64){
                llSetLinkPrimitiveParamsFast(LINK_THIS,params);
                params = [];
            }
         }
         }
        params += [PRIM_LINK_TARGET, i,
         if(llGetListLength(params) > 0){
                        PRIM_POSITION, pos,
             llSetLinkPrimitiveParamsFast(LINK_THIS,params);
                        PRIM_ROTATION, rot/rootRot,
                        PRIM_SIZE, scale
        ];
 
         if (64 < llGetListLength(params))
        {
             llSetLinkPrimitiveParamsFast(LINK_THIS, params);
             params = [];
             params = [];
         }
         }
    }
    while (++i <= primCount);
    if (llGetListLength(params))
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS, params);
        params = [];
     }
     }
}
}
 
// This function is used to start a sequential animation playback.
// If the delay speed is set too low, the script might not be able to keep up.
playAnimation(float delay, integer loop)
playAnimation(float delay, integer loop)
{
{
     if(delay < 0.1) delay = 1.0;
     if (delay < 0.1)
        delay = 1.0;
     if( loop == FALSE)
 
     if (loop == FALSE)
         playAnimationStyle = 1;
         playAnimationStyle = 1;
     else
     else
         playAnimationStyle = 2;
         playAnimationStyle = 2;
 
     if (recordedSnapshots >= 1)
     if (1 <= recordedSnapshots)
         llSetTimerEvent(delay);
         llSetTimerEvent(delay);
}
}
 
// This shows the edit menu
showMenuDialog()
showMenuDialog()
{
{
    return; // comment out line to re-enable menu
//  return;
 
     string temp = (string)((float)freeMemory/(float)maxMemory * 100.0);
     string temp = (string)((float)freeMemory/(float)maxMemory * 100.0);
     string menuText = "Available Memory: " + (string)freeMemory + " (" + llGetSubString(temp, 0, 4) +"%)" +
     string menuText = "Free Memory: " + (string)freeMemory + " (" + llGetSubString(temp, 0, 4) +"%)"
    "\nCurrent Snapshot: " + (string)currentSnapshot +"\tSnapshots Recorded: " + (string)recordedSnapshots +
        + "\nSnapshot " + (string)currentSnapshot +" of " + (string)recordedSnapshots
    "\n\n[ Record ] - Record a snapshot of prim positions\n[ Play ] - Play back all the recorded snapshots\n[ Publish ] - Finish the recording process\n[ Show Next ] - Show the next snapshot\n[ Show Prev ] - Show the previous snapshot";
        + "\n\n[ Record ] - Record a snapshot of prim positions"
        + "\n[ Play ] - Play back all the recorded snapshots"
     llDialog(llGetOwner(), menuText, ["Record","Play","Publish","Show Prev","Show Next","Loop","Stop","Export"], COMMAND_CHANNEL);
        + "\n[ Publish ] - Finish the recording process"
        + "\n[ Show Next ] - Show the next snapshot"
        + "\n[ Show Prev ] - Show the previous snapshot";
 
     llDialog(llGetOwner(), menuText,
        ["Record","Play","Publish","Show Prev","Show Next","Loop","Stop","Export"], COMMAND_CHANNEL);
}
}
string truncate_float(float foo){
string truncate_float(float foo)
     if(foo == 0.0){
{
     if (foo == 0.0)
         return "0";
         return "0";
     }else if(foo == (float)((integer)foo)){
     else if (foo == (float)((integer)foo))
         return (string)((integer)foo);
         return (string)((integer)foo);
    }
 
     string bar = (string)foo;
     string bar = (string)foo;
     while(llGetSubString(bar,-1,-1) == "0"){
 
         bar = llGetSubString(bar,0,-2);  
     while (llGetSubString(bar, -1, -1) == "0")
    }
         bar = llGetSubString(bar, 0, -2);
     if(llGetSubString(bar,-1,-1) == "."){
 
         bar = llGetSubString(bar,0,-2);
     if (llGetSubString(bar, -1, -1) == ".")
    }
         bar = llGetSubString(bar, 0, -2);
 
     return bar;
     return bar;
}
}


key op_import = "6b78fcc8-e147-4105-99a6-ff19b4bf559d";
calc_scaleChange()
key op_export = "7c2ca168-2b64-4836-8727-8e62b78dbd44";
{
key op_alter_rootScale = "f9d3389e-a78c-43f8-9e35-c11adec112a5";
     if (rootScale != ZERO_VECTOR)
calc_scaleChange(){
    {
     if (rootScale != ZERO_VECTOR){
         vector newScale = llGetScale();
         vector newScale = llGetScale();
        //since change_scale is triggered even with linked prim changes,
 
        //this is to filter out non-root changes.
         if ( (newScale.x / rootScale.x) != scaleChange.x
         if( ( newScale.x / rootScale.x) != scaleChange.x ||
            || (newScale.y / rootScale.y) != scaleChange.y
            ( newScale.y / rootScale.y) != scaleChange.y ||
            || (newScale.z / rootScale.z) != scaleChange.z)
            ( newScale.z / rootScale.z) != scaleChange.z )
         {
         {
             scaleChange.x = newScale.x / rootScale.x;
             scaleChange.x = newScale.x / rootScale.x;
Line 165: Line 166:
     }
     }
}
}
default
default
{
{
Line 171: Line 173:
         maxMemory = llGetFreeMemory();
         maxMemory = llGetFreeMemory();
         freeMemory = llGetFreeMemory();
         freeMemory = llGetFreeMemory();
 
         primCount = llGetNumberOfPrims();
         primCount = llGetNumberOfPrims();
         commandListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), "");
         commandListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), "");
         showMenuDialog();
         showMenuDialog();
 
        //setting initial root scale.  this allows the animation to scale if the root size is changed afterwards.
         rootScale = llGetScale();
         rootScale = llGetScale();
         if(llGetInventoryType("OPA Notecard Import - 2011-11-03") == INVENTORY_SCRIPT){
         if (llGetInventoryType("OPA Notecard Import - 2011-11-03") == INVENTORY_SCRIPT){
             llResetOtherScript("OPA Notecard Import - 2011-11-03");
             llResetOtherScript("OPA Notecard Import - 2011-11-03");
         }
         }
     }
     }
 
/*    //Feel free to remove this on-touch trigger if you are using your own script to control playback
// Feel free to remove this on-touch trigger if you are using your own script to control playback
    touch_start(integer num_detected)
//  touch_start(integer num_detected)
    {
//  {
        //only activate after publish.
//     if (commandListenerHandle == -1)
        if (commandListenerHandle == -1)
//      {
        {
//         if (playAnimationStyle == 0)
            //if animation not playing start it, else stop it.
//              playAnimation(1.0,TRUE);
            if( playAnimationStyle == 0)
//          else
                playAnimation(1.0,TRUE);
//          {
            else
//              playAnimationStyle = 0;
            {
//              llSetTimerEvent((float)FALSE);
                playAnimationStyle = 0;
//          }
                llSetTimerEvent(0);
//      }
            }
//  }
        }
 
    }*/
     changed(integer change)
     changed(integer change)
     {
     {
        //this is needed to detect scale changes and record the differences in order to adjust the animation accordingly.
         if (change & CHANGED_SCALE)
         if (change & CHANGED_SCALE)
        {
             calc_scaleChange();
             calc_scaleChange();
        }
 
        // if new prims are added or removed from this object then the script resets
         if (change & CHANGED_LINK)
        // because the animations are now broken.
         else if (change & CHANGED_LINK)
         {
         {
             if( primCount != llGetNumberOfPrims() )
             if ( primCount != llGetNumberOfPrims() )
             {
             {
                 llOwnerSay("Link change detected, reseting script.");
                 llOwnerSay("Link change detected, reseting script.");
Line 218: Line 213:
         }
         }
     }
     }
 
     //The message link function is to allow other scripts to control the snapshot playback
     //The message link function is to allow other scripts to control the snapshot playback
     //This command will display snapshot #2:
     //This command will display snapshot #2:
Line 231: Line 226:
     //To stop any playing animation use
     //To stop any playing animation use
     //      llMessageLinked(LINK_ROOT, 0, "XDstop", NULL_KEY);
     //      llMessageLinked(LINK_ROOT, 0, "XDstop", NULL_KEY);
     link_message(integer sender_num, integer num, string str, key id)
     link_message(integer sender_num, integer num, string str, key id)
     {
     {
         if ("XDshow" == str && num >= 1 && num <= recordedSnapshots){
         if ("XDshow" == str && 1 <= num && num <= recordedSnapshots)
             showSnapshot(num);
             show_snapshot(num);
         }else if ("XDplay" == str){
         else if ("XDplay" == str)
        {
             currentSnapshot = 1;
             currentSnapshot = 1;
             float delay = (float)((string)id);
             float delay = (float)((string)id);
             playAnimation(delay,FALSE);
             playAnimation(delay, FALSE);
         }else if ("XDplayLoop" == str){
         }
        else if ("XDplayLoop" == str)
        {
             float delay = (float)((string)id);
             float delay = (float)((string)id);
             playAnimation(delay,TRUE);
             playAnimation(delay, TRUE);
         }else if ("XDstop" == str){
         }
        else if ("XDstop" == str)
        {
             playAnimationStyle = 0;
             playAnimationStyle = 0;
             llSetTimerEvent(0);
             llSetTimerEvent((float)FALSE);
         }else if("XDexport" == str && num == 0){ // added by Marv
         }
        else if ("XDexport" == str && !num)
        {
             list export = [];
             list export = [];
             string foo;
             string foo;
Line 251: Line 254:
             rotation baa;
             rotation baa;
             string baz;
             string baz;
             integer i;
 
             integer i = 2;
             integer j = primCount;
             integer j = primCount;
             for(i=2;i<=j;++i){
 
             do
                 export += [llGetLinkName(i)];
                 export += [llGetLinkName(i)];
             }
             while (++i <= j);
            j= llGetListLength(posList);
 
             llMessageLinked(sender_num, 1, llDumpList2String(export,"|")  , op_export);
             llMessageLinked(sender_num, 1, llDumpList2String(export,"|")  , op_export);
             export = [];
             export = [];
             for(i=0;i<j;++i){
 
             i = 0;
            j = llGetListLength(posList);
 
            do
            {
                 bar = llList2Vector(posList,i);
                 bar = llList2Vector(posList,i);
                 export += ["<" + truncate_float(bar.x) + "," + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
                 export += ["<" + truncate_float(bar.x) + ","
                          + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
             }
             }
            while (++i < j);
             llMessageLinked(sender_num, 2, llDumpList2String(export,"|")  , op_export);
             llMessageLinked(sender_num, 2, llDumpList2String(export,"|")  , op_export);
             export = [];
             export = [];
             j= llGetListLength(rotList);
 
             for(i=0;i<j;++i){
            i = 0:
             j = llGetListLength(rotList);
 
            do
             {
                 baa = llList2Rot(rotList,i);
                 baa = llList2Rot(rotList,i);
                 export += ["<" + truncate_float(baa.x) + "," + truncate_float(baa.y) + "," + truncate_float(baa.z) + "," + truncate_float(baa.s) + ">"];
                 export += ["<" + truncate_float(baa.x) + "," + truncate_float(baa.y)
                            + "," + truncate_float(baa.z) + "," + truncate_float(baa.s) + ">"];
             }
             }
            while (++i < j);
             llMessageLinked(sender_num, 3, llDumpList2String(export,"|")  , op_export);
             llMessageLinked(sender_num, 3, llDumpList2String(export,"|")  , op_export);
             export = [];
             export = [];
             j= llGetListLength(scaleList);
 
             for(i=0;i<j;++i){
            i = 0;
             j = llGetListLength(scaleList);
 
            do
             {
                 bar = llList2Vector(scaleList,i);
                 bar = llList2Vector(scaleList,i);
                 export += ["<" + truncate_float(bar.x) + "," + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
                 export += ["<" + truncate_float(bar.x) + ","
                            + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
             }
             }
            while (++i < j);
             llMessageLinked(sender_num, 4, llDumpList2String(export,"|")  , op_export);
             llMessageLinked(sender_num, 4, llDumpList2String(export,"|")  , op_export);
         }else if("XDmenu" == str){
         }
        else if ("XDmenu" == str)
        {
             showMenuDialog();
             showMenuDialog();
         }else if("XDimportLength" == str && num > 0){
         }
             list foo = [];
        else if ("XDimportLength" == str && 0 < num)
             list bar = [];
        {
             list foo;
             list bar;
 
             integer i;
             integer i;
             for(i=0;i<num;++i){
             do
            {
                 foo += [ZERO_VECTOR];
                 foo += [ZERO_VECTOR];
                 bar += [ZERO_ROTATION];
                 bar += [ZERO_ROTATION];
             }
             }
            while (++i < num);
             posList = foo;
             posList = foo;
             scaleList = foo;
             scaleList = foo;
Line 295: Line 330:
             llMessageLinked(LINK_SET, recordedSnapshots, "XDrecordedSnapshots", NULL_KEY);
             llMessageLinked(LINK_SET, recordedSnapshots, "XDrecordedSnapshots", NULL_KEY);
             currentSnapshot = 1;
             currentSnapshot = 1;
         }else if("XDrecordedSnapshots" == str && num == -1){
         }
        else if ("XDrecordedSnapshots" == str && num == -1)
        {
             llMessageLinked(sender_num,recordedSnapshots,str,NULL_KEY);
             llMessageLinked(sender_num,recordedSnapshots,str,NULL_KEY);
         }else if(id == op_import && num >= 0){
         }
        else if (id == op_import && 0 <= num)
        {
             list params = llParseString2List(str, ["|"], []);
             list params = llParseString2List(str, ["|"], []);
             vector impPos = (vector)llList2String(params,0);
             vector impPos = (vector)llList2String(params, 0);
             rotation impRot = (rotation)llList2String(params,1);
             rotation impRot = (rotation)llList2String(params, 1);
             vector impSize  = (vector)llList2String(params,2);
             vector impSize  = (vector)llList2String(params, 2);
             posList = llListReplaceList(posList,[impPos],num,num);
 
             rotList = llListReplaceList(rotList,[impRot],num,num);
             posList = llListReplaceList(posList, [impPos], num, num);
             scaleList = llListReplaceList(scaleList,[impSize],num,num);
             rotList = llListReplaceList(rotList, [impRot], num, num);
         }else if(id == op_alter_rootScale){
             scaleList = llListReplaceList(scaleList, [impSize], num, num);
         }
        else if (id == op_alter_rootScale)
        {
             rootScale = (vector)str;
             rootScale = (vector)str;
             calc_scaleChange();
             calc_scaleChange();
         }
         }
     }
     }
 
    //This event handler takes care of all the editing commands.
    //Available commands are: record, play, publish, show next, show prev, show #
     listen(integer channel, string name, key id, string message)
     listen(integer channel, string name, key id, string message)
     {
     {
         list parsedMessage = llParseString2List(message, [" "], []);
         list parsedMessage = llParseString2List(message, [" "], []);
         string firstWord = llToLower(llList2String(parsedMessage,0));
         string firstWord = llToLower(llList2String(parsedMessage, 0));
         string secondWord = llToLower(llList2String(parsedMessage,1));
         string secondWord = llToLower(llList2String(parsedMessage, 1));
 
        //display a snapshot
         if ("show" == firstWord && recordedSnapshots > 0)
         if("show" == firstWord && recordedSnapshots > 0)
         {
         {
            //stop any currently playing animation.
             llSetTimerEvent((float)FALSE);
             llSetTimerEvent(0);
 
             if (secondWord == "next")
             if(secondWord == "next")
             {
             {
                 currentSnapshot++;
                 ++currentSnapshot;
                 if(currentSnapshot > recordedSnapshots)
 
                 if (recordedSnapshots < currentSnapshot)
                     currentSnapshot = 1;
                     currentSnapshot = 1;
 
                 showSnapshot(currentSnapshot);
                 show_snapshot(currentSnapshot);
             }
             }
             else if(secondWord == "prev")
             else if (secondWord == "prev")
             {
             {
                 currentSnapshot--;
                 --currentSnapshot;
                 if(currentSnapshot < 1)
 
                 if (currentSnapshot < 1)
                     currentSnapshot = recordedSnapshots;
                     currentSnapshot = recordedSnapshots;
 
                 showSnapshot(currentSnapshot);
                 show_snapshot(currentSnapshot);
             }
             }
             else
             else
             {
             {
                // when the conversion fails, snapshotNumber = 0
                 currentSnapshot = (integer)secondWord;
                 currentSnapshot = (integer)secondWord;
                 if(currentSnapshot > 0 && currentSnapshot <= recordedSnapshots )
 
                 if (currentSnapshot && currentSnapshot <= recordedSnapshots)
                 {
                 {
                     showSnapshot(currentSnapshot);
                     show_snapshot(currentSnapshot);
                     llOwnerSay("Showing snapshot: "+(string)currentSnapshot);
                     llOwnerSay("Showing snapshot: " + (string)currentSnapshot);
                 }
                 }
                 else
                 else
Line 354: Line 394:
                     llOwnerSay("Invalid snapshot number given: " + (string) currentSnapshot +
                     llOwnerSay("Invalid snapshot number given: " + (string) currentSnapshot +
                                 "\nA valid snapshot number is between 1 and " + (string) recordedSnapshots);
                                 "\nA valid snapshot number is between 1 and " + (string) recordedSnapshots);
                     currentSnapshot = 1;
                     currentSnapshot = 1;
                 }
                 }
             }
             }
         }
         }
        //record a snapshot
         else if (firstWord == "record")
         else if(firstWord == "record")
         {
         {
            integer i = 0;
            //2 is the first linked prim number.
             vector rootPos = llGetPos();
             vector rootPos = llGetPos();
             for( i = 2; i <= primCount; i++)
 
             integer i = 2;
            do
             {
             {
                 vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]),0);
                 vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]), 0);
                //need to convert into local position
 
                 pos.x -= rootPos.x;
                 pos.x -= rootPos.x;
                 pos.z -= rootPos.z;
                 pos.z -= rootPos.z;
Line 373: Line 413:
                 pos = pos / llGetRot();
                 pos = pos / llGetRot();
                 posList += pos;
                 posList += pos;
 
                 rotation rot = llList2Rot(llGetLinkPrimitiveParams(i, [PRIM_ROTATION]),0);
                 rotation rot = llList2Rot(llGetLinkPrimitiveParams(i, [PRIM_ROTATION]), 0);
                //Converting into local rot
 
                 rot = rot / llGetRot();
                 rot = rot / llGetRot();
                 rotList += rot;
                 rotList += rot;
 
                 scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0);
                 scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]), 0);
             }
             }
             recordedSnapshots++;
             while (++i <= primCount);
 
            ++recordedSnapshots;
 
             llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots);
             llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots);
             freeMemory = llGetFreeMemory();
             freeMemory = llGetFreeMemory();
         }
         }
        //play the animation from beginning to end once without looping.
         else if (firstWord == "play")
         else if (firstWord == "play")
         {
         {
             float delay = (float)secondWord;
             float delay = (float)secondWord;
             currentSnapshot = 1;
             currentSnapshot = 1;
            //play the animation once without loop
             playAnimation(delay, FALSE);
             playAnimation(delay, FALSE);
         }
         }
        //publish disables the recording features and enables the on-touch trigger
         else if ("publish" == firstWord)
         else if("publish" == firstWord)
         {
         {
            //stop any currently playing animation.
             llSetTimerEvent((float)FALSE);
             llSetTimerEvent(0);
             playAnimationStyle = 0;
             playAnimationStyle = 0;
             currentSnapshot = 1;
             currentSnapshot = 1;
 
            //remove listeners to disable recording
             llListenRemove(commandListenerHandle);
             llListenRemove(commandListenerHandle);
             commandListenerHandle = -1; //indicating that it's been published
             commandListenerHandle = -1;
 
             llOwnerSay("Recording disabled. Publish complete.\nClick me to toggle animation on/off.");
             llOwnerSay("Recording disabled. Publish complete.\nClick me to toggle animation on/off.");
         }else if("loop" == firstWord){
         }
             llMessageLinked(LINK_THIS,0,"XDplayLoop",NULL_KEY);
        else if ("loop" == firstWord)
         }else if("stop" == firstWord){
        {
             llMessageLinked(LINK_THIS,0,"XDstop",NULL_KEY);
             llMessageLinked(LINK_THIS, 0, "XDplayLoop", NULL_KEY);
         }else if("export" == firstWord){
         }
        else if ("stop" == firstWord)
        {
             llMessageLinked(LINK_THIS, 0, "XDstop", NULL_KEY);
         }
        else if ("export" == firstWord)
        {
             llOwnerSay("Should be exporting");
             llOwnerSay("Should be exporting");
             llMessageLinked(LINK_THIS,0,"XDexport",NULL_KEY);
             llMessageLinked(LINK_THIS, 0, "XDexport", NULL_KEY);
         }
         }
 
        //if not published, show menu
         if (commandListenerHandle != -1)
         if(commandListenerHandle != -1)
             showMenuDialog();
             showMenuDialog();
     }
     }
 
    //Timer event is used to handle the animation playback.
     timer()
     timer()
     {
     {
         showSnapshot(currentSnapshot);
         show_snapshot(currentSnapshot);
 
        //if not at the end of the animation, increment the counter
         if (currentSnapshot < recordedSnapshots)
         if(currentSnapshot < recordedSnapshots)
             ++currentSnapshot;
             currentSnapshot++;
         else
         else
         {
         {
            // if animation is looping, set the counter back to 1
             if (playAnimationStyle == 2)
             if( playAnimationStyle == 2)
                 currentSnapshot = 1;
                 currentSnapshot = 1;
            // if animation isn't looping, stop the animation
             else
             else
             {
             {
                 llSetTimerEvent(0);
                 llSetTimerEvent((float)FALSE);
                //if not published, show dialog menu
 
                 if(commandListenerHandle != -1)
                 if (commandListenerHandle != -1)
                     showMenuDialog();
                     showMenuDialog();
             }
             }

Revision as of 11:23, 19 October 2012

<lsl> // Open Prim Animator - by Todd Borst // Extensive Modifications by SignpostMarv Martin

// This is provided AS IS without support. Please don't bug me demanding // help or custom work for this free script.

// Summary: This is a simple prim animation script. Just add this script // to your object and a dialog will automatically pop up for you to use.

// Features: // -Single script "Prim Puppeteer" like animation tool // -Playback controllable through external scripts // -Animation is scalable and resizeable // -On-touch trigger built-in // -Completely free and open sourced

// License: // You are welcome to use this anyway you like, even bring to other grids // outside of Second Life. If you try to sell what I'm giving away for // free, you will be cursed with unimaginably bad juju.

integer COMMAND_CHANNEL = 32;

integer primCount; integer commandListenerHandle = -1;

list posList; list rotList; list scaleList; integer currentSnapshot; integer recordedSnapshots;

vector rootScale; vector scaleChange = <1.0, 1.0, 1.0>;

integer maxMemory; integer freeMemory;

// The values for playAnimationStyle means // 0 := no animation playing // 1 := play animation once // 2 := play animation looping

integer playAnimationStyle;

key op_import = "6b78fcc8-e147-4105-99a6-ff19b4bf559d"; key op_export = "7c2ca168-2b64-4836-8727-8e62b78dbd44"; key op_alter_rootScale = "f9d3389e-a78c-43f8-9e35-c11adec112a5";

// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

show_snapshot(integer snapNumber) {

   if (!snapNumber || recordedSnapshots < snapNumber)
       return;
   vector rootPos = llGetPos();
   rotation rootRot = llGetRot();
   vector pos;
   rotation rot;
   vector scale;
   list params;
   integer i = 2;
   do
   {
       pos     = llList2Vector(posList, ((snapNumber - 1)*(primCount - 1)) + (i - 2));
       rot     = llList2Rot(rotList, ((snapNumber - 1)*(primCount - 1)) + (i - 2));
       scale   = llList2Vector(scaleList, ((snapNumber - 1)*(primCount - 1)) + (i - 2));
       if ( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 )
       {
           pos.x *= scaleChange.x;
           pos.y *= scaleChange.y;
           pos.z *= scaleChange.z;
           scale.x *= scaleChange.x;
           scale.y *= scaleChange.y;
           scale.z *= scaleChange.z;
       }
       params += [PRIM_LINK_TARGET, i,
                       PRIM_POSITION, pos,
                       PRIM_ROTATION, rot/rootRot,
                       PRIM_SIZE, scale
       ];
       if (64 < llGetListLength(params))
       {
           llSetLinkPrimitiveParamsFast(LINK_THIS, params);
           params = [];
       }
   }
   while (++i <= primCount);
   if (llGetListLength(params))
   {
       llSetLinkPrimitiveParamsFast(LINK_THIS, params);
       params = [];
   }

}

playAnimation(float delay, integer loop) {

   if (delay < 0.1)
       delay = 1.0;
   if (loop == FALSE)
       playAnimationStyle = 1;
   else
       playAnimationStyle = 2;
   if (1 <= recordedSnapshots)
       llSetTimerEvent(delay);

}

showMenuDialog() { // return;

   string temp = (string)((float)freeMemory/(float)maxMemory * 100.0);
   string menuText = "Free Memory: " + (string)freeMemory + " (" + llGetSubString(temp, 0, 4) +"%)"
       + "\nSnapshot " + (string)currentSnapshot +" of " + (string)recordedSnapshots
       + "\n\n[ Record ] - Record a snapshot of prim positions"
       + "\n[ Play ] - Play back all the recorded snapshots"
       + "\n[ Publish ] - Finish the recording process"
       + "\n[ Show Next ] - Show the next snapshot"
       + "\n[ Show Prev ] - Show the previous snapshot";
   llDialog(llGetOwner(), menuText,
       ["Record","Play","Publish","Show Prev","Show Next","Loop","Stop","Export"], COMMAND_CHANNEL);

} string truncate_float(float foo) {

   if (foo == 0.0)
       return "0";
   else if (foo == (float)((integer)foo))
       return (string)((integer)foo);
   string bar = (string)foo;
   while (llGetSubString(bar, -1, -1) == "0")
       bar = llGetSubString(bar, 0, -2);
   if (llGetSubString(bar, -1, -1) == ".")
       bar = llGetSubString(bar, 0, -2);
   return bar;

}

calc_scaleChange() {

   if (rootScale != ZERO_VECTOR)
   {
       vector newScale = llGetScale();
       if ( (newScale.x / rootScale.x) != scaleChange.x
           || (newScale.y / rootScale.y) != scaleChange.y
           || (newScale.z / rootScale.z) != scaleChange.z)
       {
           scaleChange.x = newScale.x / rootScale.x;
           scaleChange.y = newScale.y / rootScale.y;
           scaleChange.z = newScale.z / rootScale.z;
       }
   }

}

default {

   state_entry()
   {
       maxMemory = llGetFreeMemory();
       freeMemory = llGetFreeMemory();
       primCount = llGetNumberOfPrims();
       commandListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), "");
       showMenuDialog();
       rootScale = llGetScale();
       if (llGetInventoryType("OPA Notecard Import - 2011-11-03") == INVENTORY_SCRIPT){
           llResetOtherScript("OPA Notecard Import - 2011-11-03");
       }
   }

// Feel free to remove this on-touch trigger if you are using your own script to control playback // touch_start(integer num_detected) // { // if (commandListenerHandle == -1) // { // if (playAnimationStyle == 0) // playAnimation(1.0,TRUE); // else // { // playAnimationStyle = 0; // llSetTimerEvent((float)FALSE); // } // } // }

   changed(integer change)
   {
       if (change & CHANGED_SCALE)
           calc_scaleChange();
       if (change & CHANGED_LINK)
       {
           if ( primCount != llGetNumberOfPrims() )
           {
               llOwnerSay("Link change detected, reseting script.");
               llResetScript();
           }
       }
   }
   //The message link function is to allow other scripts to control the snapshot playback
   //This command will display snapshot #2:
   //      llMessageLinked(LINK_ROOT, 2, "XDshow", NULL_KEY);  llSleep(1.0);
   //
   //This command will play through all the recorded snapshots in ascending order.  The number "1.0" is the delay speed and can be changed.
   //      llMessageLinked(LINK_ROOT, 0, "XDplay", "1.0");
   //
   //This command will loop through all the recorded snapshots in ascending order.  The number "1.0" is the delay speed and can be changed.
   //      llMessageLinked(LINK_ROOT, 0, "XDplayLoop", "1.0");
   //
   //To stop any playing animation use
   //      llMessageLinked(LINK_ROOT, 0, "XDstop", NULL_KEY);
   link_message(integer sender_num, integer num, string str, key id)
   {
       if ("XDshow" == str && 1 <= num && num <= recordedSnapshots)
           show_snapshot(num);
       else if ("XDplay" == str)
       {
           currentSnapshot = 1;
           float delay = (float)((string)id);
           playAnimation(delay, FALSE);
       }
       else if ("XDplayLoop" == str)
       {
           float delay = (float)((string)id);
           playAnimation(delay, TRUE);
       }
       else if ("XDstop" == str)
       {
           playAnimationStyle = 0;
           llSetTimerEvent((float)FALSE);
       }
       else if ("XDexport" == str && !num)
       {
           list export = [];
           string foo;
           vector bar;
           rotation baa;
           string baz;
           integer i = 2;
           integer j = primCount;
           do
               export += [llGetLinkName(i)];
           while (++i <= j);
           llMessageLinked(sender_num, 1, llDumpList2String(export,"|")  , op_export);
           export = [];
           i = 0;
           j = llGetListLength(posList);
           do
           {
               bar = llList2Vector(posList,i);
               export += ["<" + truncate_float(bar.x) + ","
                         + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
           }
           while (++i < j);
           llMessageLinked(sender_num, 2, llDumpList2String(export,"|")  , op_export);
           export = [];
           i = 0:
           j = llGetListLength(rotList);
           do
           {
               baa = llList2Rot(rotList,i);
               export += ["<" + truncate_float(baa.x) + "," + truncate_float(baa.y)
                           + "," + truncate_float(baa.z) + "," + truncate_float(baa.s) + ">"];
           }
           while (++i < j);
           llMessageLinked(sender_num, 3, llDumpList2String(export,"|")  , op_export);
           export = [];
           i = 0;
           j = llGetListLength(scaleList);
           do
           {
               bar = llList2Vector(scaleList,i);
               export += ["<" + truncate_float(bar.x) + ","
                           + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
           }
           while (++i < j);
           llMessageLinked(sender_num, 4, llDumpList2String(export,"|")  , op_export);
       }
       else if ("XDmenu" == str)
       {
           showMenuDialog();
       }
       else if ("XDimportLength" == str && 0 < num)
       {
           list foo;
           list bar;
           integer i;
           do
           {
               foo += [ZERO_VECTOR];
               bar += [ZERO_ROTATION];
           }
           while (++i < num);
           posList = foo;
           scaleList = foo;
           rotList = bar;
           llMessageLinked(sender_num,-1,str,op_import);
           recordedSnapshots = num / (llGetNumberOfPrims() - 1);
           llMessageLinked(LINK_SET, recordedSnapshots, "XDrecordedSnapshots", NULL_KEY);
           currentSnapshot = 1;
       }
       else if ("XDrecordedSnapshots" == str && num == -1)
       {
           llMessageLinked(sender_num,recordedSnapshots,str,NULL_KEY);
       }
       else if (id == op_import && 0 <= num)
       {
           list params = llParseString2List(str, ["|"], []);
           vector impPos = (vector)llList2String(params, 0);
           rotation impRot = (rotation)llList2String(params, 1);
           vector impSize  = (vector)llList2String(params, 2);
           posList = llListReplaceList(posList, [impPos], num, num);
           rotList = llListReplaceList(rotList, [impRot], num, num);
           scaleList = llListReplaceList(scaleList, [impSize], num, num);
       }
       else if (id == op_alter_rootScale)
       {
           rootScale = (vector)str;
           calc_scaleChange();
       }
   }
   listen(integer channel, string name, key id, string message)
   {
       list parsedMessage = llParseString2List(message, [" "], []);
       string firstWord = llToLower(llList2String(parsedMessage, 0));
       string secondWord = llToLower(llList2String(parsedMessage, 1));
       if ("show" == firstWord && recordedSnapshots > 0)
       {
           llSetTimerEvent((float)FALSE);
           if (secondWord == "next")
           {
               ++currentSnapshot;
               if (recordedSnapshots < currentSnapshot)
                   currentSnapshot = 1;
               show_snapshot(currentSnapshot);
           }
           else if (secondWord == "prev")
           {
               --currentSnapshot;
               if (currentSnapshot < 1)
                   currentSnapshot = recordedSnapshots;
               show_snapshot(currentSnapshot);
           }
           else
           {
               currentSnapshot = (integer)secondWord;
               if (currentSnapshot && currentSnapshot <= recordedSnapshots)
               {
                   show_snapshot(currentSnapshot);
                   llOwnerSay("Showing snapshot: " + (string)currentSnapshot);
               }
               else
               {
                   llOwnerSay("Invalid snapshot number given: " + (string) currentSnapshot +
                               "\nA valid snapshot number is between 1 and " + (string) recordedSnapshots);
                   currentSnapshot = 1;
               }
           }
       }
       else if (firstWord == "record")
       {
           vector rootPos = llGetPos();
           integer i = 2;
           do
           {
               vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]), 0);
               pos.x -= rootPos.x;
               pos.z -= rootPos.z;
               pos.y -= rootPos.y;
               pos = pos / llGetRot();
               posList += pos;
               rotation rot = llList2Rot(llGetLinkPrimitiveParams(i, [PRIM_ROTATION]), 0);
               rot = rot / llGetRot();
               rotList += rot;
               scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]), 0);
           }
           while (++i <= primCount);
           ++recordedSnapshots;
           llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots);
           freeMemory = llGetFreeMemory();
       }
       else if (firstWord == "play")
       {
           float delay = (float)secondWord;
           currentSnapshot = 1;
           playAnimation(delay, FALSE);
       }
       else if ("publish" == firstWord)
       {
           llSetTimerEvent((float)FALSE);
           playAnimationStyle = 0;
           currentSnapshot = 1;
           llListenRemove(commandListenerHandle);
           commandListenerHandle = -1;
           llOwnerSay("Recording disabled. Publish complete.\nClick me to toggle animation on/off.");
       }
       else if ("loop" == firstWord)
       {
           llMessageLinked(LINK_THIS, 0, "XDplayLoop", NULL_KEY);
       }
       else if ("stop" == firstWord)
       {
           llMessageLinked(LINK_THIS, 0, "XDstop", NULL_KEY);
       }
       else if ("export" == firstWord)
       {
           llOwnerSay("Should be exporting");
           llMessageLinked(LINK_THIS, 0, "XDexport", NULL_KEY);
       }
       if (commandListenerHandle != -1)
           showMenuDialog();
   }
   timer()
   {
       show_snapshot(currentSnapshot);
       if (currentSnapshot < recordedSnapshots)
           ++currentSnapshot;
       else
       {
           if (playAnimationStyle == 2)
               currentSnapshot = 1;
           else
           {
               llSetTimerEvent((float)FALSE);
               if (commandListenerHandle != -1)
                   showMenuDialog();
           }
       }
   }

} </lsl>