Resize Resize Rename Redescribe
Created by Kira Komarov.
Introduction
It has been a long time coming, I have just tried to resize a 255+ primitive linked object by using Briliant Scientist's linkset resize script and due to the big number of links, the script crashed on me. So I have decided to create my own rescale, resize script and incorporate the linkset renamer and linkset redescriber into it so that I have an universal tool to manipulate linksets when I modify my clothes.
The notable difference between this script and Briliant Scientist's resize script is that I do not store a list of sizes and positions but perform the resize on the fly. Of course, a regrettable side-effect is that by using this script, you do not have a revert or restore option to put the size of the prim back the way it was. Consequently, make sure you create a backup of the object you are manipulating, in case something goes wrong.
Overview of Features
- One of the limitations that I have found with resizer scripts, in particular when having to resize attachments and clothes, is that there is a fixed list of ratios to resize by: sometimes that little +0.05 resize is just insufficient and you just want to be able to specify a +0.02 instead which would work better in your case.
This script solves that problem by adding the [ + ] and [ - ] options which increment or decrement all the button values by 0.01. That is, although one of the default sizes is +0.05, you can press the [ - ] button and all the values will be pulled down by 0.01 so that you will get a +0.04 button.
- When creating a large object or using an in-world resale generator, you sometimes want to change the name or the description of the primitives along with it.
This script incorporates the quick renamer and description changer that we have made previously on which will allow you to block change all the names and descriptions in a linked object with one single pass.
- The script does not bound the resize and rescale values to any value.
Originally, we wanted to be able to crunch objects like we did with Briliant Scientist's script, in order to be able to compress and object even if a primitive in the link set has reached its minimal value. It is a good idea to keep the object backed-up in case you have not acheived the desired effect. The script is meant as a tool for builders and not a script that you should incorporate into a product since there are no fail-proof safety mechanisms in place.
Developer Notes
- One problem that I have faced when using my minimalist coding style, is that I got two options [ + ] and [ - ] which, for each, a loop had to be executed in order to increment or decrement the value buttons. The easiest solution is to simply write the "similar" loop twice in an if-clause, once for [ + ] and once for [ - ]. I did not like that because, in effect, I would be duplicating code just to decrease a value instead of increase. The solution that I found was the following:
<lsl>
// For both cases of + and - if(strb == "[ + ]" || strb == "[ - ]") { // We get the sign of the operation, concatenate the sign // with the string of the value we want to modify with // and then we block-cast evertying to float. Cowabunga! float mod = (float)(llGetSubString(strb, 2, 2) + (string)0.01);
</lsl> which uses llGetSubString to extract the + or - sign from the strb string (yes, just the character as a string). It then concatenates the + or - character with the string value of 0.01. So after the concatenation we get the string:
+0.01
if the button contained a + character, or:
-0.01
if the button contained a - character.
Which is great, because we can then cast that string to a float which will give us either the positive or negative value. For example:
(float)"-0.01"
gives us the negative float value of the string -0.01.
That way, I can write the loop just once and just add the value depending on the button symbol. Cowabunga!
- Another thing to mention is that I do not use a function to perform the operation but use a timer with the smallest possible value:
<lsl> llSetTimerEvent(1.175494351E-38); </lsl>
This has been discussed previously on the Teleport script and the idea is that on OpenSim, for example, event handlers like state_entry go away after a while. Thus, if you are resizing an object with a lot of linked primitives, the script may just stop mid-way because the function simply timed out. I also find it more elegant to use a timer, regardless of the small value because it does not block the VM. To understand that, you can contrast sleeping using llSleep with using a timer.
Code
<lsl>
////////////////////////////////////////////////////////// // [K] Komarov - 2012, License: GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html // // for legal details, rights of fair usage and // // the disclaimer and warranty conditions. // //////////////////////////////////////////////////////////
float _scale = 1.0; integer _sRun = 0; list __scaleMenu = ["-0.05", "-0.10", "-0.25", "+0.05", "+0.10", "+0.25", "[ DEL ]", "[ + ]", "[ - ]", "[ NAME ]", "[ DESC ]"]; string _nameOrDesc = "";
default {
touch_start(integer total_number) { key a = llDetectedKey(0); if(a != llGetOwner() || _sRun != FALSE) return; integer comChannel = ((integer)("0x"+llGetSubString((string)llGetKey(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; llListen(comChannel, "", a, ""); llDialog(a, "Please select from the options below: \n", __scaleMenu, comChannel); } listen(integer channel, string stra, key id, string strb) { if(strb == "[ + ]" || strb == "[ - ]") { integer itra=0; // We get the sign of the operation, concatenate the sign // with the string of the value we want to modify with // and then we block-cast evertying to float. Cowabunga! float mod = (float)(llGetSubString(strb, 2, 2) + (string)0.01); do { if(llFabs(llList2Float(__scaleMenu, itra)) + mod < 0.01) jump nope; } while(++itra<=5); --itra; do { stra = llGetSubString(llList2String(__scaleMenu, itra), 0, 0); strb = llGetSubString((string)(llFabs(llList2Float(__scaleMenu, itra)) + mod), 0, 3); __scaleMenu = llListReplaceList(__scaleMenu, (list)(stra + strb), itra, itra); } while(--itra>=0);
@nope;
llDialog(id, "Please select from the options below: \n", __scaleMenu, channel); return; } if(strb == "[ NAME ]") state rename; if(strb == "[ DESC ]") state describe; if(strb == "[ DEL ]") { llRemoveInventory(llGetScriptName()); return; } if((float)strb == 0) return; _scale += (float)strb; state resize; }
}
state resize {
state_entry() { llOwnerSay("Resizing, rescaling... Please wait..."); _sRun = llGetNumberOfPrims(); llSetTimerEvent(1.175494351E-38); } timer() { if(_sRun == 0) { llOwnerSay("Reize, rescale done..."); llSetTimerEvent(0); _scale = 1.0; state default; } if(_sRun == 1) { vector linkScale = llGetScale(); llSetScale(_scale * linkScale); jump next_link; } vector linkScale = llList2Vector(llGetLinkPrimitiveParams(_sRun, [PRIM_SIZE]), 0); vector linkPos = llList2Vector(llGetLinkPrimitiveParams(_sRun, [PRIM_POS_LOCAL]), 0); llSetLinkPrimitiveParamsFast(_sRun, [PRIM_SIZE, _scale * linkScale, PRIM_POSITION, _scale * linkPos]);
@next_link;
--_sRun; }
}
state rename {
state_entry() { integer comChannel = ((integer)("0x"+llGetSubString((string)llGetKey(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; llListen(comChannel, "", llGetOwner(), ""); llTextBox(llGetOwner(), "Please select a new name for every primitive: \n", comChannel); } touch_start(integer num) { // Locked? if(_nameOrDesc != "") return; llOwnerSay("Going back to default mode... Touch again for menu..."); state default; } listen(integer channel, string stra, key id, string strb) { _sRun = llGetNumberOfPrims(); // Lock _nameOrDesc = strb; llSetTimerEvent(1.175494351E-38); } timer() { if(_sRun == 0) { llOwnerSay("Rename done... Touch again for menu..."); llSetTimerEvent(0); // Unlock _nameOrDesc = ""; state default; } llSetLinkPrimitiveParamsFast(_sRun, [PRIM_NAME, _nameOrDesc]); --_sRun; }
}
state describe {
state_entry() { integer comChannel = ((integer)("0x"+llGetSubString((string)llGetKey(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; llListen(comChannel, "", llGetOwner(), ""); llTextBox(llGetOwner(), "Please select a new description for every primitive: \n", comChannel); } touch_start(integer num) { // Locked? if(_nameOrDesc != "") return; llOwnerSay("Going back to default mode... Touch again for menu..."); state default; } listen(integer channel, string stra, key id, string strb) { _sRun = llGetNumberOfPrims(); // Lock _nameOrDesc = strb; llSetTimerEvent(1.175494351E-38); } timer() { if(_sRun == 0) { llOwnerSay("Describe done... Touch again for menu..."); llSetTimerEvent(0); // Unlock _nameOrDesc = ""; state default; } llSetLinkPrimitiveParamsFast(_sRun, [PRIM_DESC, _nameOrDesc]); --_sRun; }
}
</lsl>