Open Prim Animator: Difference between revisions
Todd Borst (talk | contribs) No edit summary |
Committing changes made to OPA made over the past year at work |
||
| Line 1: | Line 1: | ||
<lsl> | <lsl> | ||
// Open Prim Animator - by Todd Borst | // Open Prim Animator - by Todd Borst | ||
// 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 15: | ||
// -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 = 0; | integer primCount = 0; | ||
integer commandListenerHandle = -1; | integer commandListenerHandle = -1; | ||
list posList = []; | list posList = []; | ||
list rotList = []; | list rotList = []; | ||
| Line 30: | Line 31: | ||
integer currentSnapshot = 0; | integer currentSnapshot = 0; | ||
integer recordedSnapshots = 0; | integer recordedSnapshots = 0; | ||
vector rootScale = ZERO_VECTOR; | vector rootScale = ZERO_VECTOR; | ||
vector scaleChange = <1,1,1>; | vector scaleChange = <1,1,1>; | ||
// For tracking memory usage. The amount of snapshots you can record is based | // 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 | // on the number of prims and available memory. Less prims = more snapshots | ||
integer maxMemory = 0; | integer maxMemory = 0; | ||
integer freeMemory = 0; | integer freeMemory = 0; | ||
integer playAnimationStyle = 0; | integer playAnimationStyle = 0; | ||
// The values for playAnimationStyle means | // The values for playAnimationStyle means | ||
| Line 44: | Line 45: | ||
// 1 = play animation once | // 1 = play animation once | ||
// 2 = play animation looping | // 2 = play animation looping | ||
// This function is used to display a recorded snapshot | // This function is used to display a recorded snapshot | ||
showSnapshot(integer snapNumber) | showSnapshot(integer snapNumber) | ||
| Line 54: | Line 55: | ||
rotation rot; | rotation rot; | ||
vector scale; | vector scale; | ||
vector rootPos = llGetPos(); | vector rootPos = llGetPos(); | ||
// Might want to move llGetRot() into the loop for fast rotating objects. | // Might want to move llGetRot() into the loop for fast rotating objects. | ||
// Rotation during the animation playback may cause errors. | // Rotation during the animation playback may cause errors. | ||
rotation rootRot = llGetRot(); | rotation rootRot = llGetRot(); | ||
list params = []; | |||
//2 is the first linked prim number. | //2 is the first linked prim number. | ||
for( i = 2; i <= primCount; i++) | for( i = 2; i <= primCount; i++) | ||
| Line 67: | Line 70: | ||
rot = llList2Rot(rotList,((snapNumber-1)*(primCount-1))+(i-2)); | rot = llList2Rot(rotList,((snapNumber-1)*(primCount-1))+(i-2)); | ||
scale = llList2Vector(scaleList,((snapNumber-1)*(primCount-1))+(i-2)); | scale = llList2Vector(scaleList,((snapNumber-1)*(primCount-1))+(i-2)); | ||
//Adjust for scale changes | //Adjust for scale changes | ||
if( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 ) | if( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 ) | ||
| Line 78: | Line 81: | ||
scale.z *= scaleChange.z; | scale.z *= scaleChange.z; | ||
} | } | ||
params += [ | |||
PRIM_LINK_TARGET, | |||
i, | |||
PRIM_POSITION, | |||
pos, | |||
PRIM_ROTATION, | |||
rot/rootRot, | |||
PRIM_SIZE, | |||
scale | |||
]; | |||
if(llGetListLength(params) > 64){ | |||
llSetLinkPrimitiveParamsFast(LINK_THIS,params); | |||
params = []; | |||
} | |||
} | |||
if(llGetListLength(params) > 0){ | |||
llSetLinkPrimitiveParamsFast(LINK_THIS,params); | |||
params = []; | |||
} | } | ||
} | } | ||
} | } | ||
// This function is used to start a sequential animation playback. | // 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. | // If the delay speed is set too low, the script might not be able to keep up. | ||
| Line 89: | Line 110: | ||
{ | { | ||
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 >= 1) | if (recordedSnapshots >= 1) | ||
llSetTimerEvent(delay); | llSetTimerEvent(delay); | ||
} | } | ||
// This shows the edit menu | // This shows the edit menu | ||
showMenuDialog() | showMenuDialog() | ||
{ | { | ||
return; // comment out line to re-enable menu | |||
string temp = (string)((float)freeMemory/(float)maxMemory * 100.0); | string temp = (string)((float)freeMemory/(float)maxMemory * 100.0); | ||
string menuText = "Available Memory: " + (string)freeMemory + " (" + llGetSubString(temp, 0, 4) +"%)" + | string menuText = "Available Memory: " + (string)freeMemory + " (" + llGetSubString(temp, 0, 4) +"%)" + | ||
"\nCurrent Snapshot: " + (string)currentSnapshot +"\tSnapshots Recorded: " + (string)recordedSnapshots + | "\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"; | "\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; | |||
} | |||
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"; | |||
calc_scaleChange(){ | |||
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; | |||
} | |||
} | |||
} | } | ||
default | default | ||
{ | { | ||
| Line 116: | Line 171: | ||
maxMemory = llGetFreeMemory(); | maxMemory = llGetFreeMemory(); | ||
freeMemory = llGetFreeMemory(); | freeMemory = llGetFreeMemory(); | ||
primCount = llGetNumberOfPrims(); | primCount = llGetNumberOfPrims(); | ||
commandListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), ""); | commandListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), ""); | ||
showMenuDialog(); | showMenuDialog(); | ||
//setting initial root scale. this allows the animation to scale if the root size is changed afterwards. | //setting initial root scale. this allows the animation to scale if the root size is changed afterwards. | ||
rootScale = llGetScale(); | 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) | touch_start(integer num_detected) | ||
{ | { | ||
| Line 140: | Line 198: | ||
} | } | ||
} | } | ||
} | }*/ | ||
changed(integer change) | changed(integer change) | ||
{ | { | ||
| Line 147: | Line 205: | ||
if (change & CHANGED_SCALE) | if (change & CHANGED_SCALE) | ||
{ | { | ||
calc_scaleChange(); | |||
} | } | ||
// if new prims are added or removed from this object then the script resets | // if new prims are added or removed from this object then the script resets | ||
| Line 173: | Line 218: | ||
} | } | ||
} | } | ||
//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 188: | Line 233: | ||
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 >= 1 && num <= recordedSnapshots) | if ("XDshow" == str && num >= 1 && num <= recordedSnapshots){ | ||
showSnapshot(num); | showSnapshot(num); | ||
else if ("XDplay" == str) | }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){ | ||
float delay = (float)((string)id); | float delay = (float)((string)id); | ||
playAnimation(delay,TRUE); | playAnimation(delay,TRUE); | ||
} | }else if ("XDstop" == str){ | ||
playAnimationStyle = 0; | playAnimationStyle = 0; | ||
llSetTimerEvent(0); | llSetTimerEvent(0); | ||
}else if("XDexport" == str && num == 0){ // added by Marv | |||
list export = []; | |||
string foo; | |||
vector bar; | |||
rotation baa; | |||
string baz; | |||
integer i; | |||
integer j = primCount; | |||
for(i=2;i<=j;++i){ | |||
export += [llGetLinkName(i)]; | |||
} | |||
j= llGetListLength(posList); | |||
llMessageLinked(sender_num, 1, llDumpList2String(export,"|") , op_export); | |||
export = []; | |||
for(i=0;i<j;++i){ | |||
bar = llList2Vector(posList,i); | |||
export += ["<" + truncate_float(bar.x) + "," + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"]; | |||
} | |||
llMessageLinked(sender_num, 2, llDumpList2String(export,"|") , op_export); | |||
export = []; | |||
j= llGetListLength(rotList); | |||
for(i=0;i<j;++i){ | |||
baa = llList2Rot(rotList,i); | |||
export += ["<" + truncate_float(baa.x) + "," + truncate_float(baa.y) + "," + truncate_float(baa.z) + "," + truncate_float(baa.s) + ">"]; | |||
} | |||
llMessageLinked(sender_num, 3, llDumpList2String(export,"|") , op_export); | |||
export = []; | |||
j= llGetListLength(scaleList); | |||
for(i=0;i<j;++i){ | |||
bar = llList2Vector(scaleList,i); | |||
export += ["<" + truncate_float(bar.x) + "," + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"]; | |||
} | |||
llMessageLinked(sender_num, 4, llDumpList2String(export,"|") , op_export); | |||
}else if("XDmenu" == str){ | |||
showMenuDialog(); | |||
}else if("XDimportLength" == str && num > 0){ | |||
list foo = []; | |||
list bar = []; | |||
integer i; | |||
for(i=0;i<num;++i){ | |||
foo += [ZERO_VECTOR]; | |||
bar += [ZERO_ROTATION]; | |||
} | |||
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 && num >= 0){ | |||
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(); | |||
} | } | ||
} | } | ||
//This event handler takes care of all the editing commands. | //This event handler takes care of all the editing commands. | ||
//Available commands are: record, play, publish, show next, show prev, show # | //Available commands are: record, play, publish, show next, show prev, show # | ||
| Line 215: | Line 318: | ||
string firstWord = llToLower(llList2String(parsedMessage,0)); | string firstWord = llToLower(llList2String(parsedMessage,0)); | ||
string secondWord = llToLower(llList2String(parsedMessage,1)); | string secondWord = llToLower(llList2String(parsedMessage,1)); | ||
//display a snapshot | //display a snapshot | ||
if("show" == firstWord && recordedSnapshots > 0) | if("show" == firstWord && recordedSnapshots > 0) | ||
| Line 221: | Line 324: | ||
//stop any currently playing animation. | //stop any currently playing animation. | ||
llSetTimerEvent(0); | llSetTimerEvent(0); | ||
if(secondWord == "next") | if(secondWord == "next") | ||
{ | { | ||
| Line 227: | Line 330: | ||
if(currentSnapshot > recordedSnapshots) | if(currentSnapshot > recordedSnapshots) | ||
currentSnapshot = 1; | currentSnapshot = 1; | ||
showSnapshot(currentSnapshot); | showSnapshot(currentSnapshot); | ||
} | } | ||
| Line 235: | Line 338: | ||
if(currentSnapshot < 1) | if(currentSnapshot < 1) | ||
currentSnapshot = recordedSnapshots; | currentSnapshot = recordedSnapshots; | ||
showSnapshot(currentSnapshot); | showSnapshot(currentSnapshot); | ||
} | } | ||
| Line 270: | Line 373: | ||
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); | ||
//Converting into local rot | //Converting into local rot | ||
rot = rot / llGetRot(); | rot = rot / llGetRot(); | ||
rotList += rot; | rotList += rot; | ||
scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0); | scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0); | ||
} | } | ||
recordedSnapshots++; | recordedSnapshots++; | ||
llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots); | llOwnerSay("Total number of snapshots recorded: " + (string)recordedSnapshots); | ||
freeMemory = llGetFreeMemory(); | freeMemory = llGetFreeMemory(); | ||
| Line 298: | Line 401: | ||
playAnimationStyle = 0; | playAnimationStyle = 0; | ||
currentSnapshot = 1; | currentSnapshot = 1; | ||
//remove listeners to disable recording | //remove listeners to disable recording | ||
llListenRemove(commandListenerHandle); | llListenRemove(commandListenerHandle); | ||
commandListenerHandle = -1; //indicating that it's been published | commandListenerHandle = -1; //indicating that it's been published | ||
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("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 not published, show menu | //if not published, show menu | ||
if(commandListenerHandle != -1) | if(commandListenerHandle != -1) | ||
showMenuDialog(); | showMenuDialog(); | ||
} | } | ||
//Timer event is used to handle the animation playback. | //Timer event is used to handle the animation playback. | ||
timer() | timer() | ||
{ | { | ||
showSnapshot(currentSnapshot); | showSnapshot(currentSnapshot); | ||
//if not at the end of the animation, increment the counter | //if not at the end of the animation, increment the counter | ||
if(currentSnapshot < recordedSnapshots) | if(currentSnapshot < recordedSnapshots) | ||
Revision as of 04:06, 14 December 2011
<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 = 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();
list params = [];
//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;
}
params += [
PRIM_LINK_TARGET,
i,
PRIM_POSITION,
pos,
PRIM_ROTATION,
rot/rootRot,
PRIM_SIZE,
scale
];
if(llGetListLength(params) > 64){
llSetLinkPrimitiveParamsFast(LINK_THIS,params);
params = [];
}
}
if(llGetListLength(params) > 0){
llSetLinkPrimitiveParamsFast(LINK_THIS,params);
params = [];
}
}
}
// 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() {
return; // comment out line to re-enable menu
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","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;
}
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"; calc_scaleChange(){
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;
}
}
} 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();
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)
{
//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)
{
calc_scaleChange();
}
// 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);
}else if("XDexport" == str && num == 0){ // added by Marv
list export = [];
string foo;
vector bar;
rotation baa;
string baz;
integer i;
integer j = primCount;
for(i=2;i<=j;++i){
export += [llGetLinkName(i)];
}
j= llGetListLength(posList);
llMessageLinked(sender_num, 1, llDumpList2String(export,"|") , op_export);
export = [];
for(i=0;i<j;++i){
bar = llList2Vector(posList,i);
export += ["<" + truncate_float(bar.x) + "," + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
}
llMessageLinked(sender_num, 2, llDumpList2String(export,"|") , op_export);
export = [];
j= llGetListLength(rotList);
for(i=0;i<j;++i){
baa = llList2Rot(rotList,i);
export += ["<" + truncate_float(baa.x) + "," + truncate_float(baa.y) + "," + truncate_float(baa.z) + "," + truncate_float(baa.s) + ">"];
}
llMessageLinked(sender_num, 3, llDumpList2String(export,"|") , op_export);
export = [];
j= llGetListLength(scaleList);
for(i=0;i<j;++i){
bar = llList2Vector(scaleList,i);
export += ["<" + truncate_float(bar.x) + "," + truncate_float(bar.y) + "," + truncate_float(bar.z) + ">"];
}
llMessageLinked(sender_num, 4, llDumpList2String(export,"|") , op_export);
}else if("XDmenu" == str){
showMenuDialog();
}else if("XDimportLength" == str && num > 0){
list foo = [];
list bar = [];
integer i;
for(i=0;i<num;++i){
foo += [ZERO_VECTOR];
bar += [ZERO_ROTATION];
}
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 && num >= 0){
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();
}
}
//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.");
}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 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>