- New Year's Revision of the code added. Yay!
Let me know if I broke anything.
Edit: I did. Posted a fix for cylinders and prisms. Let me know if I broke anything else.
CODE
//============================================================================
// Prim Mirroring Script Set
// Written by Jeffrey Gomez
//
// Permissions Granted to Edit, Copy, Transfer, and Sell this script
// to any user, so long as this comment set remains intact, and is
// granted WITHOUT ANY WARRANTY. USE AT OWN RISK. And enjoy. =]
//
//
// Original Date of Creation: March 8th, 2005
// Last Date of Revision: January 9th, 2005
//
// Any unauthorized or illegal usage of this script, as dictated by
// International Laws of Copyright or Linden Labs voids any license to use
// this script. Creator of this script is not responsible for said use.
//
// So please, don't come after me. =)
//
//
// Forum Thread URL(s):
// http://forums.secondlife.com/showthread.php?t=38165
//
//
// Script Purpose and Usage:
// This script is used to mirror prims. That's about it!
//
// To use this script set place the Prim Mirror Code in a second prim.
// That's it! Now when you want to mirror something (relative to this second
// prim), merely drop the appropriate Mirror Code into the item (primitive)
// that you wish to mirror. The script will do the work for you.
//
// You may rotate the mirror prim around to get different angles, or scale it
// to get different sizes of mirroring. Note scaling appears odd for this -
// that's a factor of how prims work, so don't blame me!
//
// Script Limitations:
// - This Script DOES NOT support Prim Torturing in ANY form.
//============================================================================
//====================== Constants.Begin =====================
vector AXIS = <0,0,1>; // Defines axis to mirror (X,Y,Z). Checks Booleans only!
float RANGE = 10.0; // Defines range of sensor for mirroring.
string KEY = // Key value for sensor
"";
string NAME = // Name value for sensor
"Prim Mirror Base";
string MESSAGE = // Error message if not in range.
"Hey! You need to have the mirror rezzed and nearby to use this! How else do I know what to mirror against? Touch to continue.";
//====================== Constants.End =====================
//====================== Global_Variables.Begin =====================
vector pos; // Current Prim's Position
rotation rot; // Current Prim's Rotation
vector size; // Current Prim's Scale
integer type; // Current Prim's Prim Type
integer holeshape; // Current Prim's Hollow Shape
float hollow; // Current Prim's Hollow Size
vector holesize; // Current Prim's Wrap Radius
vector cut; // Current Prim's Cut
vector twist; // Current Prim's Twist
vector topsize; // Current Prim's Top Size
vector topshear; // Current Prim's Top Shear
vector dimple; // Current Prim's Dimple
vector advancedcut; // Current Prim's Advanced Cut
vector taper; // Current Prim's Taper
float revolutions; // Current Prim's Number of Revolutions
float radiusoffset; // Current Prim's Radius Delta
float skew; // Current Prim's Skew
//====================== Global_Variables.End =====================
//====================== Global_Functions.Begin =====================
// GetParams: Fills global variable namespaces with current primitive params
GetParams()
{
// Dump our params to a list and return ...
list params = llGetPrimitiveParams([PRIM_POSITION,PRIM_ROTATION,PRIM_SIZE,PRIM_TYPE]);
pos = llList2Vector(params,0); // ... position...
rot = llList2Rot(params,1); // ... rotation ...
size = llList2Vector(params,2); // ... scale ...
type = llList2Integer(params,3); // ... type ...
holeshape = llList2Integer(params,4); // ... holeshape ...
cut = llList2Vector(params,5); // ... cut ...
hollow = llList2Float(params,6); // ... hole amount ...
twist = llList2Vector(params,7); // ... twist ...
// ... and use the type to check the next series of operations
if(type < 3) // If this is a box, cylinder, or prism, return ...
{
topsize = llList2Vector(params,8); // ... top size ...
topshear = llList2Vector(params,9); // ... and top shear.
}
else if(type == 3) // If this is a sphere, return...
{
dimple = llList2Vector(params,8); // ... dimple.
}
else if(type > 3) // If this is a tube, torus, or ring, return ...
{
holesize = llList2Vector(params,8); // ... hole size ...
topshear = llList2Vector(params,9); // ... top shear ...
advancedcut = llList2Vector(params,10); // ... advanced cut ...
taper = llList2Vector(params,11); // ... taper ...
revolutions = llList2Float(params,12); // ... revolutions ...
radiusoffset = llList2Float(params,13); // ... radius delta ...
skew = llList2Float(params,14); // ... and skew.
}
}
//====================== Global_Functions.End =====================
//====================== State_Functions.Begin =====================
default
{
sensor(integer total_number) // Sensor_Event.begin
{
// Local_Variables.begin
integer i; // Top level loop count
integer j; // Nested loop count
vector relPos; // Relative frame position
rotation relRot; // Relative frame rotation
vector relRot2; // Rotation as a Euler
integer count = // Sums booleans for flip loops
llAbs((integer)AXIS.x) + llAbs((integer)AXIS.y) + llAbs((integer)AXIS.z);
// Local_Variables.end
// Statements.begin
GetParams(); // Calls GetParams
for(i = 0; i < total_number; ++i) // Sensor_Loop.begin
{
if(llDetectedGroup(i)) // Group_If.begin
{
// Gets position relative to mirror
relPos = (pos - llDetectedPos(i)) / llDetectedRot(i);
// Gets rotation relative to mirror
relRot = rot / llDetectedRot(i);
// Stores this rotation as a Euler
relRot2 = llRot2Euler(relRot);
// Box, Cylinder, Prism:
if(type < 3)
{
for(j = 0; j < count; ++j) // Nest_Loop.begin
{
// Flips stuff based on number of times mirroring
cut = <1 - cut.y, 1 - cut.x, 0>;
topshear = <topshear.y,topshear.x,0>;
topsize = <topsize.y,topsize.x,0>;
twist *= -1;
size = <size.y,size.x,size.z>;
} // Nest_Loop.end
if(AXIS.x) // If X Axis option is set...
{
relPos.x *= -1;
relRot2.y *= -1;
relRot2.z *= -1;
relRot2 = llRot2Euler(<0.00000, 0.00000, 0.70711, 0.70711> * llEuler2Rot(relRot2));
}
if(AXIS.y) // If Y Axis option is set...
{
relPos.y *= -1;
relRot2.x *= -1;
relRot2.z *= -1;
relRot2 = llRot2Euler(<0.00000, 0.00000, -0.70711, 0.70711> * llEuler2Rot(relRot2));
}
if(AXIS.z) // If Z Axis option is set...
{
relPos.z *= -1;
relRot2.x *= -1;
relRot2.y *= -1;
relRot2 = llRot2Euler(<-0.70711, -0.70711, -0.00000, 0.00000> * llEuler2Rot(relRot2));
}
if(type == 2 || type == 1) // If this is a cylinder or prism:
{
for(j = 0; j < count; ++j) // Nest_Loop.begin
{
topshear = <topshear.y,-1 * topshear.x,0>;
topsize = <topsize.y,topsize.x,0>;
relRot2.z += PI_BY_TWO;
size = <size.y,size.x,size.z>;
} // Nest_Loop.end
}
}
// Sphere:
else if(type == 3)
{
for(j = 0; j < count; ++j) // Nest_Loop.begin
{
cut = <1 - cut.y, 1 - cut.x, 0>;
twist = <twist.y,twist.x,0>;
} // Nest_Loop.end
if(AXIS.x) // If X Axis option is set...
{
relPos.x *= -1;
relRot2.z *= -1;
relRot2.y *= -1;
relRot2 = llRot2Euler(<-0.00000, -1.00000, -0.00000, 0.00000> * llEuler2Rot(relRot2));
}
if(AXIS.y) // If Y Axis option is set...
{
relPos.y *= -1;
relRot2.x *= -1;
relRot2.z *= -1;
relRot2 = llRot2Euler(<1.00000, -0.00000, -0.00000, 0.00000> * llEuler2Rot(relRot2));
}
if(AXIS.z) // If Z Axis option is set...
{
relPos.z *= -1;
relRot2.x *= -1;
relRot2.y *= -1;
}
}
// Torus, tube, ring:
else if(type > 3)
{
for(j = 0; j < count; ++j) // Nest_Loop.begin
{
cut = <1 - cut.y, 1 - cut.x, 0>;
twist = <twist.y,twist.x,0>;
topshear = <topshear.x * -1,topshear.y * -1,0>;
taper *= -1;
radiusoffset *= -1;
skew *= -1;
} // Nest_Loop.end
if(AXIS.x) // If X Axis option is set...
{
relPos.x *= -1;
relRot2.y *= -1;
relRot2.y += PI;
}
if(AXIS.y) // If Y Axis option is set...
{
relPos.y *= -1;
relRot2.x *= -1;
relRot2.x += PI;
relRot2.y *= -1;
}
if(AXIS.z) // If Z Axis option is set...
{
relPos.z *= -1;
relRot2.x *= -1;
relRot2 += <PI,PI,PI>;
}
}
// Set back the relative rotation
relRot = llEuler2Rot(relRot2);
// Set the sim-level position
pos = llDetectedPos(i) + (relPos * llDetectedRot(i));
// Set the sim-level rotation
rot = relRot * llDetectedRot(i);
// Uncomment for items exceeding 10m
// NOTE you may need to take globals into account!
//while(llGetPos() != pos)
//llSetPos(pos);
if(type < 3) // Box, Cylinder, Prism:
{
llSetPrimitiveParams([PRIM_POSITION,pos,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_TYPE,type,holeshape,cut,hollow,twist,topsize,topshear]);
}
else if(type == 3) // Sphere:
{
llSetPrimitiveParams([PRIM_POSITION,pos,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_TYPE,type,holeshape,cut,hollow,twist,dimple]);
}
else if(type > 3) // Tube, Torus, Ring:
{
llSetPrimitiveParams([PRIM_POSITION,pos,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_TYPE,type,holeshape,cut,hollow,twist,holesize,topshear,advancedcut,taper,revolutions,radiusoffset,skew]);
}
// If we got here, remove this script from inventory
llRemoveInventory(llGetScriptName());
// Statements.end
} // Group_If.end
} // Sensor_Loop.end
} // Sensor_Event.end
state_entry() // Always called at start of script
{
llSensor(NAME,KEY,ACTIVE | PASSIVE, RANGE, TWO_PI); // Call sensor
}
touch_start(integer total_number) // Frustration mode catcher
{
llSensor(NAME,KEY,ACTIVE | PASSIVE, RANGE, TWO_PI); // Call sensor
}
no_sensor() // Called if mirror not in range
{
llOwnerSay(MESSAGE); // If not found, send the owner a cute little message
}
}
//====================== State_Functions.End =====================
// Great stuff, yeah?
And the new code for the mirror prim itself!
CODE
default
{
state_entry()
{
llSetObjectName("Prim Mirror Base"); // T'ain't much here, McGee.
}
}
No, I'm not kidding. It needed that much of a cleanup job.