Difference between revisions of "Open Prim Animator"
Jump to navigation
Jump to search
m (categorisation) |
m (<lsl> tag to <source>) |
||
(4 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
< | <source lang="lsl2"> | ||
// 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 | // 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. | // 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 18: | ||
// -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. | // 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 COMMAND_CHANNEL = 32; | ||
integer primCount | integer primCount; | ||
integer commandListenerHandle = | integer commandListenerHandle = ERR_GENERIC; | ||
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 170: | ||
} | } | ||
} | } | ||
default | default | ||
{ | { | ||
Line 171: | Line 177: | ||
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 == ERR_GENERIC) | |||
// { | |||
// 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 217: | ||
} | } | ||
} | } | ||
//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 230: | ||
//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 258: | ||
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 334: | ||
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 398: | ||
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 417: | ||
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 != ERR_GENERIC) | |||
if(commandListenerHandle != | |||
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 != | if (commandListenerHandle != ERR_GENERIC) | ||
showMenuDialog(); | showMenuDialog(); | ||
} | } | ||
Line 445: | Line 487: | ||
} | } | ||
} | } | ||
</ | </source> | ||
[[Category:Open Prim Animator|Open Prim Animator]] | [[Category:Open Prim Animator|Open Prim Animator]] |
Latest revision as of 07:15, 25 January 2015
// 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();
}
}
}
}