Open Prim Animator

From Second Life Wiki
Revision as of 11:15, 6 March 2014 by Vex Streeter (talk | contribs) (Fix typo (colon instead of semicolon))
Jump to navigation Jump to search

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

// Note from Todd to other editors: Please document changes you have made to get proper credit. // Note from Todd to users: People may have edited the script from since I've posted it originally. // You can always view the original script by clicking the history tab.

// 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. You are welcomed to sell it if you've made your // own improvements to it. This is effectively public domain. Have fun.

integer COMMAND_CHANNEL = 32;

integer primCount; integer commandListenerHandle = ERR_GENERIC;

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 == ERR_GENERIC) // { // 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 != ERR_GENERIC)
           showMenuDialog();
   }
   timer()
   {
       show_snapshot(currentSnapshot);
       if (currentSnapshot < recordedSnapshots)
           ++currentSnapshot;
       else
       {
           if (playAnimationStyle == 2)
               currentSnapshot = 1;
           else
           {
               llSetTimerEvent((float)FALSE);
               if (commandListenerHandle != ERR_GENERIC)
                   showMenuDialog();
           }
       }
   }

} </lsl>