Difference between revisions of "Open Prim Animator"
m (categorisation) |
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!) |
||
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 | integer primCount; | ||
integer commandListenerHandle = -1; | integer commandListenerHandle = -1; | ||
list posList | list posList; | ||
list rotList | list rotList; | ||
list scaleList | list scaleList; | ||
integer currentSnapshot | integer currentSnapshot; | ||
integer recordedSnapshots | integer recordedSnapshots; | ||
vector rootScale | vector rootScale; | ||
vector scaleChange = <1,1,1>; | vector scaleChange = <1.0, 1.0, 1.0>; | ||
integer maxMemory; | |||
integer freeMemory; | |||
integer maxMemory | |||
integer freeMemory | // The values for playAnimationStyle means | ||
// 0 := no animation playing | |||
// 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"; | |||
// | key op_export = "7c2ca168-2b64-4836-8727-8e62b78dbd44"; | ||
key op_alter_rootScale = "f9d3389e-a78c-43f8-9e35-c11adec112a5"; | |||
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ | |||
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ | |||
show_snapshot(integer snapNumber) | |||
{ | { | ||
if(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, | |||
if(llGetListLength(params) | 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 = []; | |||
} | } | ||
} | } | ||
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 | if (1 <= recordedSnapshots) | ||
llSetTimerEvent(delay); | llSetTimerEvent(delay); | ||
} | } | ||
showMenuDialog() | showMenuDialog() | ||
{ | { | ||
// return; | |||
string temp = (string)((float)freeMemory/(float)maxMemory * 100.0); | string temp = (string)((float)freeMemory/(float)maxMemory * 100.0); | ||
string menuText = " | 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" | |||
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)) | |||
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; | ||
} | } | ||
calc_scaleChange() | |||
{ | |||
if (rootScale != ZERO_VECTOR) | |||
calc_scaleChange(){ | { | ||
if (rootScale != ZERO_VECTOR){ | |||
vector newScale = llGetScale(); | vector newScale = llGetScale(); | ||
if ( (newScale.x / rootScale.x) != scaleChange.x | |||
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.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(); | ||
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 | |||
// touch_start(integer num_detected) | |||
// { | |||
// if (commandListenerHandle == -1) | |||
// { | |||
// if (playAnimationStyle == 0) | |||
// playAnimation(1.0,TRUE); | |||
// else | |||
// { | |||
// playAnimationStyle = 0; | |||
// llSetTimerEvent((float)FALSE); | |||
// } | |||
// } | |||
// } | |||
changed(integer change) | changed(integer change) | ||
{ | { | ||
if (change & CHANGED_SCALE) | if (change & CHANGED_SCALE) | ||
calc_scaleChange(); | calc_scaleChange(); | ||
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 | if ("XDshow" == str && 1 <= num && num <= recordedSnapshots) | ||
show_snapshot(num); | |||
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( | llSetTimerEvent((float)FALSE); | ||
}else if("XDexport" == str && num | } | ||
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; | ||
do | |||
export += [llGetLinkName(i)]; | export += [llGetLinkName(i)]; | ||
while (++i <= j); | |||
llMessageLinked(sender_num, 1, llDumpList2String(export,"|") , op_export); | llMessageLinked(sender_num, 1, llDumpList2String(export,"|") , op_export); | ||
export = []; | export = []; | ||
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); | |||
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); | |||
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 | } | ||
list foo | else if ("XDimportLength" == str && 0 < num) | ||
list bar | { | ||
list foo; | |||
list bar; | |||
integer i; | integer 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 | } | ||
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(); | ||
} | } | ||
} | } | ||
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)); | ||
if ("show" == firstWord && recordedSnapshots > 0) | |||
if("show" == firstWord && recordedSnapshots > 0) | |||
{ | { | ||
llSetTimerEvent((float)FALSE); | |||
llSetTimerEvent( | |||
if (secondWord == "next") | |||
if(secondWord == "next") | |||
{ | { | ||
++currentSnapshot; | |||
if(currentSnapshot | |||
if (recordedSnapshots < currentSnapshot) | |||
currentSnapshot = 1; | currentSnapshot = 1; | ||
show_snapshot(currentSnapshot); | |||
} | } | ||
else if(secondWord == "prev") | else if (secondWord == "prev") | ||
{ | { | ||
--currentSnapshot; | |||
if(currentSnapshot < 1) | |||
if (currentSnapshot < 1) | |||
currentSnapshot = recordedSnapshots; | currentSnapshot = recordedSnapshots; | ||
show_snapshot(currentSnapshot); | |||
} | } | ||
else | else | ||
{ | { | ||
currentSnapshot = (integer)secondWord; | currentSnapshot = (integer)secondWord; | ||
if(currentSnapshot | |||
if (currentSnapshot && currentSnapshot <= recordedSnapshots) | |||
{ | { | ||
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; | ||
} | } | ||
} | } | ||
} | } | ||
else if (firstWord == "record") | |||
else if(firstWord == "record") | |||
{ | { | ||
vector rootPos = llGetPos(); | vector rootPos = llGetPos(); | ||
integer i = 2; | |||
do | |||
{ | { | ||
vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]),0); | vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]), 0); | ||
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); | ||
rot = rot / llGetRot(); | rot = rot / llGetRot(); | ||
rotList += rot; | rotList += rot; | ||
scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0); | scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]), 0); | ||
} | } | ||
while (++i <= primCount); | |||
++recordedSnapshots; | |||
llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots); | llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots); | ||
freeMemory = llGetFreeMemory(); | freeMemory = llGetFreeMemory(); | ||
} | } | ||
else if (firstWord == "play") | else if (firstWord == "play") | ||
{ | { | ||
float delay = (float)secondWord; | float delay = (float)secondWord; | ||
currentSnapshot = 1; | currentSnapshot = 1; | ||
playAnimation(delay, FALSE); | playAnimation(delay, FALSE); | ||
} | } | ||
else if ("publish" == firstWord) | |||
else if("publish" == firstWord) | |||
{ | { | ||
llSetTimerEvent((float)FALSE); | |||
llSetTimerEvent( | |||
playAnimationStyle = 0; | playAnimationStyle = 0; | ||
currentSnapshot = 1; | currentSnapshot = 1; | ||
llListenRemove(commandListenerHandle); | llListenRemove(commandListenerHandle); | ||
commandListenerHandle = -1; | 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 (commandListenerHandle != -1) | |||
if(commandListenerHandle != -1) | |||
showMenuDialog(); | showMenuDialog(); | ||
} | } | ||
timer() | timer() | ||
{ | { | ||
show_snapshot(currentSnapshot); | |||
if (currentSnapshot < recordedSnapshots) | |||
if(currentSnapshot < recordedSnapshots) | ++currentSnapshot; | ||
else | else | ||
{ | { | ||
if (playAnimationStyle == 2) | |||
if( playAnimationStyle == 2) | |||
currentSnapshot = 1; | currentSnapshot = 1; | ||
else | else | ||
{ | { | ||
llSetTimerEvent( | llSetTimerEvent((float)FALSE); | ||
if(commandListenerHandle != -1) | if (commandListenerHandle != -1) | ||
showMenuDialog(); | showMenuDialog(); | ||
} | } |
Revision as of 10: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>