Difference between revisions of "Linkset Resizer 2"
Emma Nowhere (talk | contribs) m (moved User:Emma Nowhere/Linkset Resizer to Linkset Resizer 2: Make easier to find with other scripts in the LSL script library) |
Emma Nowhere (talk | contribs) |
||
Line 48: | Line 48: | ||
// If using in a product with no other scripts, change START_ON_TOUCH below to TRUE | // If using in a product with no other scripts, change START_ON_TOUCH below to TRUE | ||
// so user can initiate resizing by just touching the object. | // so user can initiate resizing by just touching the object. | ||
integer START_ON_TOUCH = FALSE; | integer START_ON_TOUCH = FALSE; | ||
// Display status messages in chat window (to owner only) | // Display status messages in chat window (to owner only) | ||
integer SAY_STATUS = TRUE; | integer SAY_STATUS = TRUE; | ||
// Channel to listen for commands on | // Channel to listen for commands on | ||
integer CHAT_CHANNEL = 1; | integer CHAT_CHANNEL = 1; | ||
// SL constraints | // SL constraints | ||
float MIN_SIZE = .01; | float MIN_SIZE = .01; | ||
float MAX_SIZE = 10; | float MAX_SIZE = 10; | ||
float MAX_DISTANCE = 10; | float MAX_DISTANCE = 10; | ||
float MIN_SCALE = .1; | float MIN_SCALE = .1; | ||
integer MENU_CHANNEL = -1001; | integer MENU_CHANNEL = -1001; | ||
list backupPrims = []; | list backupPrims = []; | ||
integer backupStored = FALSE; | integer backupStored = FALSE; | ||
float scale = 1.0; | float scale = 1.0; | ||
init_menu_channel() { | init_menu_channel() { | ||
MENU_CHANNEL = ((integer)("0x" + llGetSubString((string)llGetKey(), -8, -1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; | MENU_CHANNEL = ((integer)("0x" + llGetSubString((string)llGetKey(), -8, -1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; | ||
} | } | ||
say_status(string msg) { | say_status(string msg) { | ||
if (SAY_STATUS) llOwnerSay(msg); | if (SAY_STATUS) llOwnerSay(msg); | ||
} | } | ||
backup() { | backup() { | ||
if (!backupStored) { | if (!backupStored) { | ||
Line 132: | Line 132: | ||
llRemoveInventory(llGetScriptName()); | llRemoveInventory(llGetScriptName()); | ||
} | } | ||
float min(float a, float b) { | float min(float a, float b) { | ||
if (a < b) return a; | if (a < b) return a; | ||
return b; | return b; | ||
} | } | ||
float max(float a, float b) { | float max(float a, float b) { | ||
if (a > b) return a; | if (a > b) return a; | ||
return b; | return b; | ||
} | } | ||
float constrainMinMax(float value, float min, float max) { | float constrainMinMax(float value, float min, float max) { | ||
value = max(value, min); | value = max(value, min); | ||
Line 148: | Line 148: | ||
return value; | return value; | ||
} | } | ||
vector constrainSize(vector size) { | |||
size.x = constrainMinMax(size.x, MIN_SIZE, MAX_SIZE); | |||
size.y = constrainMinMax(size.y, MIN_SIZE, MAX_SIZE); | |||
size.z = constrainMinMax(size.z, MIN_SIZE, MAX_SIZE); | |||
return size; | |||
} | } | ||
vector constrainDistance(vector delta) { | |||
delta.x = min(delta.x, MAX_DISTANCE); | |||
delta.y = min(delta.y, MAX_DISTANCE); | |||
delta.z = min(delta.z, MAX_DISTANCE); | |||
return delta; | |||
} | } | ||
Line 168: | Line 174: | ||
vector size = llList2Vector(backupPrims, ((i - 1) * 2) + 1); | vector size = llList2Vector(backupPrims, ((i - 1) * 2) + 1); | ||
size | size = constrainSize(size * scale); | ||
if (i == 1) { | if (i == 1) { | ||
llSetLinkPrimitiveParamsFast(i, [PRIM_SIZE, size]); | llSetLinkPrimitiveParamsFast(i, [PRIM_SIZE, size]); | ||
} | } | ||
else { | else { | ||
pos = pos * scale | pos = constrainDistance(pos * scale); | ||
llSetLinkPrimitiveParamsFast(i, [PRIM_POSITION, pos, PRIM_SIZE, size]); | llSetLinkPrimitiveParamsFast(i, [PRIM_POSITION, pos, PRIM_SIZE, size]); | ||
} | } | ||
Line 185: | Line 186: | ||
say_status("Prims resized."); | say_status("Prims resized."); | ||
} | } | ||
menu() { | menu() { | ||
llDialog(llGetOwner(), | llDialog(llGetOwner(), | ||
Line 191: | Line 192: | ||
["Revert", "-", "Finish", "-1%", "-5%", "-10%", "+1%", "+5%", "+10%"], MENU_CHANNEL); | ["Revert", "-", "Finish", "-1%", "-5%", "-10%", "+1%", "+5%", "+10%"], MENU_CHANNEL); | ||
} | } | ||
handle_message(integer channel, string name, key id, string message) | handle_message(integer channel, string name, key id, string message) | ||
{ | { | ||
Line 225: | Line 226: | ||
} | } | ||
} | } | ||
} | } | ||
default | default | ||
{ | { | ||
Line 240: | Line 241: | ||
else { | else { | ||
llListen(CHAT_CHANNEL, "", llGetOwner(), ""); | llListen(CHAT_CHANNEL, "", llGetOwner(), ""); | ||
init_menu_channel(); | init_menu_channel(); | ||
llListen(MENU_CHANNEL, "", llGetOwner(), ""); | llListen(MENU_CHANNEL, "", llGetOwner(), ""); | ||
llOwnerSay("Resizer Ready"); | llOwnerSay("Resizer Ready"); | ||
llOwnerSay("Type /" + (string)CHAT_CHANNEL + "resizer for menu."); | llOwnerSay("Type /" + (string)CHAT_CHANNEL + "resizer for menu."); | ||
Line 259: | Line 260: | ||
} | } | ||
} | } | ||
state start_on_touch | state start_on_touch | ||
{ | { | ||
Line 265: | Line 266: | ||
{ | { | ||
llListen(CHAT_CHANNEL, "", llGetOwner(), ""); | llListen(CHAT_CHANNEL, "", llGetOwner(), ""); | ||
init_menu_channel(); | init_menu_channel(); | ||
llListen(MENU_CHANNEL, "", llGetOwner(), ""); | llListen(MENU_CHANNEL, "", llGetOwner(), ""); | ||
llOwnerSay("Resizer Ready"); | llOwnerSay("Resizer Ready"); | ||
llOwnerSay("Touch for resizer menu."); | llOwnerSay("Touch for resizer menu."); | ||
Line 282: | Line 283: | ||
handle_message(channel, name, id, message); | handle_message(channel, name, id, message); | ||
} | } | ||
touch_start(integer num_detected) | touch_start(integer num_detected) | ||
{ | { | ||
menu(); | menu(); | ||
} | } | ||
} | } | ||
</lsl> | </lsl> | ||
</div></div> | </div></div> | ||
{{#vardefine:sort| | {{#vardefine:sort|Link Resizer 2}}{{LSLC|Library}} |
Revision as of 09:26, 2 June 2010
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
About
Resizer by Emma Nowhere
Yet another object resizer script. Seeing as I was the person who originally opened the JIRA for LLGetLinkPrimitiveParams I thought I should put it to good use. I like it more than the other resizer scripts out there, but of course, I'm biased. In any case, it never hurts to have more code being shared.
How to use with menu:
- Install this script in the root prim of a linked set of prims (aka "linkset")
- Type /1resizer to show the menu
- Hit the appropriate buttons to scale up or down the linkset
- Hit the "Finish" button to remove the script and finalize prim sizes
Optionally, enter the percentage directly via chat by typing /1resizer x% where x is the percentage of the original size you want to resize to.
IMPORTANT: You should always make a backup copy of the object before using this script.
The script below is configured to be used as a drop-in script for a user or builder that wants to resize something for themselves. If putting into a product, you may want to set START_ON_TOUCH to be TRUE so that your customers can just touch the object to start resizing. You may also want to set SAY_STATUS to FALSE so that a bunch of text doesn't get sent to the chat window (only seen by the owner, but can still be annoying to the end-user).
Resizer
<lsl> /////////////////////////////////////////////////////////////////////////////// // Resizer // by Emma Nowhere // // Last modified: 6/1/2010 // // How to use with menu: // 1. Install this script in the root prim of a linked set of prims (aka "linkset") // 2. Type /1resizer to show the menu // 3. Hit the appropriate buttons to scale up or down the linkset // 4. Hit the "Finish" button to remove the script and finalize prim sizes // // Optionally, enter the percentage directly via chat by typing /1resizer x% // where x is the percentage of the original size you want to resize to. // // If using in a product with no other scripts, change START_ON_TOUCH below to TRUE // so user can initiate resizing by just touching the object.
integer START_ON_TOUCH = FALSE;
// Display status messages in chat window (to owner only)
integer SAY_STATUS = TRUE;
// Channel to listen for commands on
integer CHAT_CHANNEL = 1;
// SL constraints
float MIN_SIZE = .01; float MAX_SIZE = 10; float MAX_DISTANCE = 10; float MIN_SCALE = .1;
integer MENU_CHANNEL = -1001;
list backupPrims = []; integer backupStored = FALSE;
float scale = 1.0;
init_menu_channel() {
MENU_CHANNEL = ((integer)("0x" + llGetSubString((string)llGetKey(), -8, -1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
}
say_status(string msg) {
if (SAY_STATUS) llOwnerSay(msg);
}
backup() {
if (!backupStored) { say_status("Backing up prim positions and sizes."); backupPrims = []; integer p = llGetNumberOfPrims(); integer i = 0; vector root_pos = <0, 0, 0>; for (i = 1; i <= p; i++) { list params = llGetLinkPrimitiveParams(i, [PRIM_POSITION, PRIM_SIZE]); vector pos = llList2Vector(params, 0); vector size = llList2Vector(params, 1); if (i == 1) { root_pos = pos; } else { pos = pos - root_pos; } backupPrims = backupPrims + pos + size; } backupStored = TRUE; say_status("Prim positions and sizes backed up."); }
}
restore() {
if (backupStored) { say_status("Restoring previously backed up positions and sizes."); integer p = llGetNumberOfPrims(); integer i = 0; for (i = 1; i <= p; i++) { vector pos = llList2Vector(backupPrims, (i - 1) * 2); vector size = llList2Vector(backupPrims, ((i - 1) * 2) + 1); if (i == 1) { llSetLinkPrimitiveParamsFast(i, [PRIM_SIZE, size]); } else { llSetLinkPrimitiveParamsFast(i, [PRIM_POSITION, pos, PRIM_SIZE, size]); } } say_status("Previously backed up prim positions and sizes restored."); } scale = 1;
}
finish() {
say_status("Deleting Resizer script."); llRemoveInventory(llGetScriptName());
}
float min(float a, float b) {
if (a < b) return a; return b;
}
float max(float a, float b) {
if (a > b) return a; return b;
}
float constrainMinMax(float value, float min, float max) {
value = max(value, min); value = min(value, max); return value;
}
vector constrainSize(vector size) {
size.x = constrainMinMax(size.x, MIN_SIZE, MAX_SIZE); size.y = constrainMinMax(size.y, MIN_SIZE, MAX_SIZE); size.z = constrainMinMax(size.z, MIN_SIZE, MAX_SIZE); return size;
}
vector constrainDistance(vector delta) {
delta.x = min(delta.x, MAX_DISTANCE); delta.y = min(delta.y, MAX_DISTANCE); delta.z = min(delta.z, MAX_DISTANCE); return delta;
}
process() {
backup(); say_status("Resizing prims to " + (string)llRound(scale * 100) + "% of original size."); integer p = llGetNumberOfPrims(); integer i = 0; for (i = 1; i <= p; i++) { vector pos = llList2Vector(backupPrims, (i - 1) * 2); vector size = llList2Vector(backupPrims, ((i - 1) * 2) + 1); size = constrainSize(size * scale); if (i == 1) { llSetLinkPrimitiveParamsFast(i, [PRIM_SIZE, size]); } else { pos = constrainDistance(pos * scale); llSetLinkPrimitiveParamsFast(i, [PRIM_POSITION, pos, PRIM_SIZE, size]); } } say_status("Prims resized.");
}
menu() {
llDialog(llGetOwner(), "Resizer\n\nMake a backup of your object first.\n\nPlease choose an option:\n", ["Revert", "-", "Finish", "-1%", "-5%", "-10%", "+1%", "+5%", "+10%"], MENU_CHANNEL);
}
handle_message(integer channel, string name, key id, string message) {
if (channel == CHAT_CHANNEL) { if (message == "resizer") { menu(); } else if (llSubStringIndex(message, "resizer") == 0) { list params = llParseString2List(message, [" "], [] ); if (llGetListLength(params) == 2) { string scale_param = llList2String(params, 1); if (llGetSubString(scale_param, -1, -1) == "%") { scale = (((float)llGetSubString(scale_param, 0, -2)) / 100); scale = max(scale, MIN_SCALE); process(); } } } } else if (channel == MENU_CHANNEL) { if (message == "Revert") { restore(); menu(); } else if (message == "Finish") { finish(); } else if (llGetSubString(message, -1, -1) == "%") { scale = scale + (((float)llGetSubString(message, 0, -2)) / 100); scale = max(scale, MIN_SCALE); process(); menu(); } }
}
default {
state_entry() { if (START_ON_TOUCH) { // we only want a touch_start handler if we're going to use it // so change state rather than just testing inside touch_start // for START_ON_TOUCH to be true. state start_on_touch; } else { llListen(CHAT_CHANNEL, "", llGetOwner(), ""); init_menu_channel(); llListen(MENU_CHANNEL, "", llGetOwner(), ""); llOwnerSay("Resizer Ready"); llOwnerSay("Type /" + (string)CHAT_CHANNEL + "resizer for menu."); } } on_rez(integer start_param) { llOwnerSay("Resizer Installed"); llOwnerSay("Type /" + (string)CHAT_CHANNEL + "resizer for menu."); } listen(integer channel, string name, key id, string message) { handle_message(channel, name, id, message); }
}
state start_on_touch {
state_entry() { llListen(CHAT_CHANNEL, "", llGetOwner(), ""); init_menu_channel(); llListen(MENU_CHANNEL, "", llGetOwner(), ""); llOwnerSay("Resizer Ready"); llOwnerSay("Touch for resizer menu."); } on_rez(integer start_param) { llOwnerSay("Resizer Installed"); llOwnerSay("Touch for resizer menu."); } listen(integer channel, string name, key id, string message) { handle_message(channel, name, id, message); } touch_start(integer num_detected) { menu(); }
}
</lsl>