Open Prim Animator

From Second Life Wiki
Revision as of 11:23, 19 October 2012 by Kireji Haiku (talk | contribs) (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!)
Jump to navigation Jump to search

<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>