CameraSynch2

From Second Life Wiki
Revision as of 13:15, 24 January 2015 by ObviousAltIsObvious Resident (talk | contribs) (<lsl> tag to <source>)
Jump to navigation Jump to search

CameraSynch2 v1.0.0

Synchronization of multiple avatar cameras.
This script initially needs to be dropped individually into numerous linked prims.
However because the script adds a PIN, after its been added once the owner can issue the "update" command to automatically propogate any changes made to the root script into the child prims/scripts.

TO USE:
1] Rez a bunch of prims, one for each bum you want to sit on them.
2] Link them together.
3] Drop a copy of this script in each prim.
4] Sit one person on the controller seat, and some persons on the other seats.
5] Read the spam when you sit down.

//
// BELOG Hax
// AEST 20071221 0452 [SLT:  20071220 1152]
//  https://wiki.secondlife.com/wiki/CameraSynch2
//
// VERSION:
//  v1.0.0 revised and wikified from my previous: 'CameraSynch v0.3.1'
//      Not really well tested, but seems good. 
//      Timer frequency could do with some moderation... Possibly with dynamic adjustment.
//
// CREDITS:
//  Meyermagic Salome and Nomad Padar for
//  http://wiki.secondlife.com/wiki/Camera_Sync
//  I drew some inspiration from theirs some time after I wrote the first iteration of this script.
//  I don't think I actually derived anything from it... 
//  but theirs was the original..and Nomad is awesome.
//=========================================================================
// ---LICENCE START---
// http://creativecommons.org/licenses/by-sa/3.0/
// ie: Attribution licence:
//   Give me credit by leaving it in the script I created.
//   Supply my original script with your modified version.
//   Refer to the wiki URL from which you copied this script.
//      https://wiki.secondlife.com/wiki/CameraSynch2
// ---LICENCE END---
//=========================================================================

// SHARED CONFIGURATION
integer     gPayloadPIN         = 89876847;
//----------------------------------
// CONFIGURATION
float       gFrequency          = 0.02;
integer     gChan               = 0;
//----------------------------------
// CORE CODE - controller
string      gCamController              = NULL_KEY;
vector      gOldCamPos;
rotation    gOldCamRot;
string      gOldDesc;
integer     gTog;
// CORE CODE -  spectator
//--------------------------------------
f_camDefault()
{   llSetCameraParams([
        CAMERA_ACTIVE, FALSE, //1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 10.0, //(0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.0, //(0 to 3) seconds
        CAMERA_DISTANCE, 3.0, //(0.5 to 10) meters
        CAMERA_FOCUS_LAG, 0.1 , //(0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, //(TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 1.0, //(0 to 4) meters
        CAMERA_PITCH, 0.0, //(-45 to 80) degrees
        CAMERA_POSITION_LAG, 0.1, //(0 to 3) seconds
        CAMERA_POSITION_LOCKED, FALSE, //(TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 1.0, //(0 to 4) meters
        CAMERA_FOCUS_OFFSET, ZERO_VECTOR //<-10,-10,-10> to <10,10,10> meters
    ]);
}
//----------------------------------
default
{   on_rez(integer start_param)
    {   llResetScript();
    }    
    state_entry()
    {   if (gPayloadPIN)    llSetRemoteScriptAccessPin(gPayloadPIN);
        llSitTarget(<0.2, 0.0, 0.5>, <0.0, 0.0, 0.0, 1.0>);                 
        integer link = llGetLinkNumber();
        if (link>1)
        {   string name = "Spectator#"+(string)(link-1);
            llSetObjectName(name);
            llSetColor(<0.0, 1.0, 1.0>, ALL_SIDES);            
            llSetText(name, <1.0, 1.0, 1.0>, 1.0);
            state repeater;
        }
        llSetColor(<1.0, 1.0, 0.0>, ALL_SIDES);
        llSetObjectName(llGetScriptName());        
        llSetText("CONTROLLER", <1.0, 1.0, 1.0>,1.0);        
        if (gPayloadPIN)
            llListen(gChan, "", llGetOwner(), "update");        
    }
    listen(integer channel, string name, key id, string message)
    {   integer cc;
        integer c = cc = llGetNumberOfPrims();
        llOwnerSay("WAIT: Propogating scripts...");    
        while(c>1)
        {   llSetText("Updating: "+(string)(cc-c+1)+"/"+(string)(cc-1)
                , <1.0, 1.0, 1.0>, 1.0);
            llRemoteLoadScriptPin(llGetLinkKey(c--), llGetScriptName(), gPayloadPIN, TRUE, 1);   
        }
        llSetText("CONTROLLER", <1.0, 1.0, 1.0>, 1.0); 
        llOwnerSay("OK: Script propogation completed.");
    }
    changed(integer change)
    {   if (change & CHANGED_LINK)
        {   gCamController = llAvatarOnSitTarget();
            if (gCamController != NULL_KEY)
            {   llRequestPermissions(gCamController
                    , PERMISSION_TRACK_CAMERA|PERMISSION_TAKE_CONTROLS
                );
            }
            else
            {   llSetTimerEvent(0.0);
                llSetObjectDesc(gOldDesc);
                llResetScript();
            }
        }
    }
    run_time_permissions(integer perm)
    {   if(perm & PERMISSION_TAKE_CONTROLS)        
        {   llTakeControls(0| CONTROL_LBUTTON,TRUE, TRUE); //work anywhere
            llInstantMessage(llGetPermissionsKey(), 
                "\nThis device allows the spectator cameras to be controlled by YOU."
                +"\nUseful Tips:"
                +"\n1] Ensure you are NOT in mouselook."
                +"\n2] Spectators cameras track yours with a short delay, and do not move quite as smoothly "
                +"as yours does, so go slowly and avoid any sudden or disconcerting movements."
                +"\nREMEMBER: If your drawdistance is greater than a spectators, their camera may be left "
                +"behind at some point. So if you hear people say 'did we stop moving?' you should move "
                +"your camera closer to where you are all sitting."
            );
            llSetTimerEvent(gFrequency);
        }
        else //never
            llUnSit(gCamController);
    }
    timer()
    {   vector camPos = llGetCameraPos();
        rotation camRot = llGetCameraRot();
        if (llVecDist(camPos, gOldCamPos) > 0.001 
        || llAngleBetween(camRot, gOldCamRot) >= 0.0008)
        {   gTog = !gTog;
            gOldCamPos = camPos;
            gOldCamRot = camRot;
            llSetText("RELAYING..",<0.0, (float)gTog, 1.0-gTog>,1.0);
            llSetObjectDesc((string)camPos+"#"+(string)camRot);      
        }
    }
}
//=========================================================================
state repeater
{   on_rez(integer start_param)
    {   llResetScript();
    }
    state_entry()
    {   llSetTimerEvent(0.0);
    }
    changed(integer change)
    {   if (change & CHANGED_LINK)
        {   if (llGetLinkNumber() == 0)
                llResetScript();
            key av = llAvatarOnSitTarget();
            if (av != NULL_KEY && llGetPermissionsKey() == NULL_KEY)
            {   llRequestPermissions(av, PERMISSION_CONTROL_CAMERA);
            }
        }
    }
    run_time_permissions(integer perms)
    {   if (perms & PERMISSION_CONTROL_CAMERA)
        {   llInstantMessage(llGetPermissionsKey(), 
                "This device allows the spectator cameras to be centrally controlled."
                +"\nPlease : "
                +"\n1] Ensure you are NOT in mouselook."
                +"\n2] Reset your camera by pushing the escape button 3 or 4 times."
                +"\nNOTE: If the controller avatar's drawdistance is greater than yours, "
                +"you may experience being 'left behind' at some point. Either increase "
                +"your draw distance, or reset your camera again  (hit escape a few times) "
                +"after a short while and hopefully the controllers camera is closer and "
                +"tracking will resume.\nObviously it helps to let the controller know if "
                +"they are too far away, but perhaps your drawdistance could also be higher."
                +"\n[ctrl-P.... graphics tab...'custom' checkbox... 'drawdistance' slider... increase it a bit]"
            );
            llSetTimerEvent(gFrequency);
        }
    }
    timer()
    {   if (llGetPermissionsKey())
        {   string desc = llList2String(llGetObjectDetails(llGetLinkKey(LINK_ROOT), [OBJECT_DESC]),0); 
            integer index = llSubStringIndex(desc, "#");
            vector pos = (vector)llGetSubString(desc, 0, index-1);
            if (pos == ZERO_VECTOR)
            {   f_camDefault();
                return;
            }
            rotation rot = (rotation)llGetSubString(desc, index+1, -1);
            llSetCameraParams([
                CAMERA_ACTIVE, 1 //1 is active, 0 is inactive
                ,CAMERA_BEHINDNESS_ANGLE, 0.0 //(0 to 180) degrees
//                    ,CAMERA_BEHINDNESS_LAG, 0.05 //(0 to 3) seconds
                ,CAMERA_DISTANCE, 0.0 //(0.5 to 10) meters
                ,CAMERA_FOCUS, pos + llRot2Fwd(rot) //Region-relative
                ,CAMERA_FOCUS_LAG, 0.05 //(0 to 3) seconds
                ,CAMERA_FOCUS_LOCKED, TRUE //(TRUE or FALSE)
                ,CAMERA_FOCUS_THRESHOLD, 0.0 //(0 to 4) meters
                ,CAMERA_POSITION, pos //Region-relative position
                ,CAMERA_POSITION_LAG, 0.05 //(0 to 3) seconds
                ,CAMERA_POSITION_LOCKED, TRUE //(TRUE or FALSE)
                ,CAMERA_POSITION_THRESHOLD, 0.0 //(0 to 4) meters
                ,CAMERA_FOCUS_OFFSET, ZERO_VECTOR //<-10,-10,-10> to <10,10,10> meters
            ]);
        }
        else
        {   llSetTimerEvent(0.0);
        }
    }
}
//=========================================================================