Difference between revisions of "User:Todd Borst"

From Second Life Wiki
Jump to: navigation, search
(Open Prim Animator)
 
(Blanked the page)
 
Line 1: Line 1:
<lsl>
 
// Open Prim Animator - by Todd Borst
 
  
// 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 = 0;
 
integer commandListenerHandle = -1;
 
 
list posList    = [];
 
list rotList    = [];
 
list scaleList  = [];
 
integer currentSnapshot  = 0;
 
integer recordedSnapshots = 0;
 
 
vector rootScale  = ZERO_VECTOR;
 
vector scaleChange = <1,1,1>;
 
 
// For tracking memory usage.  The amount of snapshots you can record is based
 
// on the number of prims and available memory.  Less prims = more snapshots
 
integer maxMemory  = 0;
 
integer freeMemory = 0;
 
 
integer playAnimationStyle = 0;
 
// The values for playAnimationStyle means
 
// 0 = no animation playing
 
// 1 = play animation once
 
// 2 = play animation looping
 
 
// This function is used to display a recorded snapshot
 
showSnapshot(integer snapNumber)
 
{
 
    if(snapNumber > 0 && snapNumber <= recordedSnapshots )
 
    {
 
        integer i = 0;
 
        vector  pos;
 
        rotation rot;
 
        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();
 
 
        //2 is the first linked prim number.
 
        for( i = 2; i <= primCount; i++)
 
        {
 
            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));
 
 
            //Adjust for scale changes
 
            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;
 
            }
 
 
            llSetLinkPrimitiveParamsFast( i, [ PRIM_POSITION, pos, PRIM_ROTATION, rot/rootRot, PRIM_SIZE, scale ] );
 
        }
 
    }
 
}
 
 
// 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)
 
{
 
  if(delay < 0.1) delay = 1.0;
 
 
  if( loop == FALSE)
 
  playAnimationStyle = 1;
 
  else
 
  playAnimationStyle = 2;
 
 
  if (recordedSnapshots >= 1)
 
  llSetTimerEvent(delay);
 
}
 
 
// This shows the edit menu
 
showMenuDialog()
 
{
 
    string temp = (string)((float)freeMemory/(float)maxMemory * 100.0);
 
    string menuText = "Available Memory: " + (string)freeMemory + " (" + llGetSubString(temp, 0, 4) +"%)" +
 
    "\nCurrent Snapshot: " + (string)currentSnapshot +"\tSnapshots Recorded: " + (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"], COMMAND_CHANNEL);
 
}
 
 
default
 
{
 
    state_entry()
 
    {
 
        maxMemory = llGetFreeMemory();
 
        freeMemory = llGetFreeMemory();
 
       
 
        primCount = llGetNumberOfPrims();
 
        commandListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), "");
 
        showMenuDialog();
 
 
        //setting initial root scale.  this allows the animation to scale if the root size is changed afterwards.
 
        rootScale = llGetScale();
 
    }
 
   
 
    //Feel free to remove this on-touch trigger if you are using your own script to control playback
 
    touch_start(integer num_detected)
 
    {
 
        //only activate after publish.
 
        if (commandListenerHandle == -1)
 
{
 
//if animation not playing start it, else stop it.
 
if( playAnimationStyle == 0)
 
playAnimation(1.0,TRUE);
 
else
 
{
 
playAnimationStyle = 0;
 
llSetTimerEvent(0);
 
}
 
}
 
    }
 
 
    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 (rootScale != ZERO_VECTOR)
 
            {
 
                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 ||
 
                    ( 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;
 
                }
 
            }
 
        }
 
// if new prims are added or removed from this object then the script resets
 
// because the animations are now broken.
 
else 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 && num >= 1 && num <= recordedSnapshots)
 
            showSnapshot(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(0);
 
}
 
    }
 
 
//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)
 
    {
 
        list parsedMessage = llParseString2List(message, [" "], []);
 
        string firstWord = llToLower(llList2String(parsedMessage,0));
 
        string secondWord = llToLower(llList2String(parsedMessage,1));
 
 
//display a snapshot
 
        if("show" == firstWord && recordedSnapshots > 0)
 
        {
 
//stop any currently playing animation.
 
llSetTimerEvent(0);
 
 
            if(secondWord == "next")
 
            {
 
                currentSnapshot++;
 
                if(currentSnapshot > recordedSnapshots)
 
                    currentSnapshot = 1;
 
                   
 
                showSnapshot(currentSnapshot);
 
            }
 
            else if(secondWord == "prev")
 
            {
 
                currentSnapshot--;
 
                if(currentSnapshot < 1)
 
                    currentSnapshot = recordedSnapshots;
 
 
                showSnapshot(currentSnapshot);
 
            }
 
            else
 
            {
 
                // when the conversion fails, snapshotNumber = 0
 
                currentSnapshot = (integer)secondWord;
 
                if(currentSnapshot > 0 && currentSnapshot <= recordedSnapshots )
 
                {
 
                    showSnapshot(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;
 
                }
 
            }
 
        }
 
//record a snapshot
 
        else if(firstWord == "record")
 
        {
 
            integer i = 0;
 
            //2 is the first linked prim number.
 
            vector rootPos = llGetPos();
 
            for( i = 2; i <= primCount; i++)
 
            {
 
                vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]),0);
 
                //need to convert into local position
 
                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);
 
                //Converting into local rot
 
                rot = rot / llGetRot();
 
                rotList += rot;
 
 
                scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0);
 
            }
 
            recordedSnapshots++;
 
 
            llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots);
 
            freeMemory = llGetFreeMemory();
 
        }
 
//play the animation from beginning to end once without looping.
 
        else if (firstWord == "play")
 
        {
 
            float delay = (float)secondWord;
 
currentSnapshot = 1;
 
//play the animation once without loop
 
playAnimation(delay, FALSE);
 
        }
 
        //publish disables the recording features and enables the on-touch trigger
 
        else if("publish" == firstWord)
 
        {
 
//stop any currently playing animation.
 
llSetTimerEvent(0);
 
playAnimationStyle = 0;
 
currentSnapshot = 1;
 
 
//remove listeners to disable recording
 
            llListenRemove(commandListenerHandle);
 
            commandListenerHandle = -1; //indicating that it's been published
 
 
            llOwnerSay("Recording disabled. Publish complete.\nClick me to toggle animation on/off.");
 
        }
 
 
        //if not published, show menu
 
        if(commandListenerHandle != -1)
 
            showMenuDialog();
 
    }
 
 
//Timer event is used to handle the animation playback.
 
timer()
 
    {
 
showSnapshot(currentSnapshot);
 
 
//if not at the end of the animation, increment the counter
 
if(currentSnapshot < recordedSnapshots)
 
currentSnapshot++;
 
else
 
{
 
// if animation is looping, set the counter back to 1
 
if( playAnimationStyle == 2)
 
currentSnapshot = 1;
 
// if animation isn't looping, stop the animation
 
else
 
{
 
llSetTimerEvent(0);
 
//if not published, show dialog menu
 
if(commandListenerHandle != -1)
 
showMenuDialog();
 
}
 
}
 
}
 
}
 
</lsl>
 

Latest revision as of 08:02, 18 January 2011