Hierarchics2

From Second Life Wiki
Jump to navigation Jump to search

This is a script for creating parametrically driven hierarchies within a linked object.

The use-cases are varied and diverse, for example: User Interfaces (HUD/Vendor/Others..), Limbs (Robotic/Organic), Turrets, Machinery...

Scaling may be buggy, but position and rotation should work fine.

/*/
        Hierarchics2
    created by Nexii
    Released into Public Domain
/*/



//////////////////////
// Hierarchics2
list hName;
list hLink;
list hPtrs;
list hPos;
list hRot;
list hScl;

BuildTree() {
    list Names; list Links; hName = hLink = hPtrs = hPos = hRot = hScl = [];
    integer x = llGetNumberOfPrims();
    do {
        string Name = llGetLinkName(x);
        if( llGetSubString(Name,0,0) == "h" ) {
            Names += Name; Links += x; }
    } while( --x > 1 );
    integer z = x = llGetListLength(Names); integer y;
    while( x-- ) {
        string   rootName = llList2String(Names,x);
        integer  rootLink = llList2Integer(Links,x);
        list     rootTier = llParseString2List(rootName, ["."], []);
        integer  rootTiers = llGetListLength(rootTier);
        
        integer PtrA; integer PtrB;
        integer Children; y = z;
        while( y-- ) {
                // Is the same? Skip.
            if(y == x) jump skip;
            string   childName = llList2String(Names,y);
            list     childTier = llParseString2List(childName, ["."], []);
            integer  childTiers = llGetListLength(childTier);
                // Isn't directly below? Skip.
            if(rootTiers+1 != childTiers) jump skip;
            integer lastTier = rootTiers-1;
                // Isn't same root? Skip.
            if(llList2String(rootTier,lastTier) != llList2String(childTier,lastTier)) jump skip;
                // Otherwise, add as child
            if(Children >= 4)
                 PtrB = PtrB | ( (y+1) << (Children-4)*8 );
            else PtrA = PtrA | ( (y+1) << Children*8 );
            ++Children;
            @skip;
        }
        hName   = [rootName] + hName;
        hLink   = [rootLink] + hLink;
        hPtrs   = [0,PtrA,PtrB] + hPtrs;
    }
    x = z;
    while( x-- ) {
        string Name = llList2String(hName,x);
        integer cLink = llList2Integer(hLink,x);
        list Tier = llParseString2List(Name,["."],[]);
        integer Tiers = llGetListLength(Tier);
        
        vector cPos = (llList2Vector(llGetLinkPrimitiveParams(cLink,[PRIM_POSITION]),0)-llGetRootPosition())/llGetRootRotation();
        rotation cRot = llList2Rot(llGetLinkPrimitiveParams(cLink,[PRIM_ROTATION]),0)/llGetRootRotation();
        if(Tiers > 1) {
            integer Find = llListFindList( hName, [llDumpList2String(llList2List(Tier,0,Tiers-2),".")] );
            hPtrs = llListReplaceList(hPtrs,[Find+1],x*3,x*3);
            integer rLink = llList2Integer(hLink,Find);
            vector rPos = (llList2Vector(llGetLinkPrimitiveParams(rLink,[PRIM_POSITION]),0)-llGetRootPosition())/llGetRootRotation();
            rotation rRot = llList2Rot(llGetLinkPrimitiveParams(rLink,[PRIM_ROTATION]),0)/llGetRootRotation();
            
            cPos = (cPos-rPos)/rRot; cRot /= rRot;
        }
        hPos    = [cPos] + hPos;
        hRot    = [cRot] + hRot;
        hScl    = llGetLinkPrimitiveParams(cLink,[PRIM_SIZE]) + hScl;
    }
}

// Usage: UpdateTree([PRIM_POSITION,"Turret",<1,2,3>]);
UpdateTree( list Input ) {
    integer Find; integer Root;
    integer Operation = llList2Integer(Input,0);
    if(llGetListEntryType(Input,1) == TYPE_STRING) {
        Root = TRUE;
        Find = llListFindList( hName, [llList2String(Input,1)]);
        if(Find == -1) return;
    } else Find = llList2Integer(Input,1);
    
    list Params;
    
    if(Root) {
        vector rPos; rotation rRot;
        list lPos; list lRot;
        integer Lookup = llList2Integer(hPtrs,Find*3);
        integer x; integer y;
        while( Lookup-- ) {
            lPos = [llList2Vector(hPos,Lookup)] + lPos;
            lRot = [llList2Rot(hRot,Lookup)] + lRot;
            Lookup = llList2Integer(hPtrs,Lookup*3); ++y;
        } rPos = llList2Vector( lPos,0);
        for( x = 1; x < y; ++x ) {
            rRot = llList2Rot(lRot, x-1) * rRot;
            rPos += llList2Vector(lPos,x) * rRot; }
        if(y>1) rRot = llList2Rot(lRot,-1) * rRot;
        
        if(Operation == PRIM_POSITION) {
            vector cPos = llList2Vector(hPos,Find);
            vector tPos = llList2Vector(Input,2);
            Params = [PRIM_POSITION, rPos+(tPos*rRot)];
            hPos = llListReplaceList(hPos,[tPos],Find,Find);
            Input = [rPos+(tPos*rRot), llList2Rot(hRot,Find)*rRot];
        } else if(Operation == PRIM_ROTATION) {
            rotation tRot = llList2Rot(Input,2);
            Params = [PRIM_ROTATION, (tRot*rRot)/llGetRootRotation()];
            hRot = llListReplaceList(hRot,[tRot],Find,Find);
            Input = [rPos+(llList2Vector(hPos,Find)*rRot), tRot*rRot];
        } else if(Operation == PRIM_SIZE) {
            vector cScl = llList2Vector(hScl,Find);
            vector tScl = llList2Vector(Input,2);
            Params = [PRIM_SIZE, tScl];
            hScl = llListReplaceList(hScl,[tScl],Find,Find);
            Input = [rPos+(llList2Vector(hPos,Find)*rRot), llList2Rot(hRot,Find)*rRot,
                     <tScl.x/cScl.x,tScl.y/cScl.y,tScl.z/cScl.z>];
        }
    } else {
        Root = llList2Integer(Input,2);
        vector rPos = llList2Vector(Input,3);
        rotation rRot = llList2Rot(Input,4);
        if(Operation == PRIM_POSITION) {
            vector cPos = llList2Vector(hPos,Find);
            Params = [PRIM_POSITION, rPos+(cPos*rRot)];
            Input = [rPos+(cPos*rRot),llList2Rot(hRot,Find)*rRot];
        } else if(Operation == PRIM_ROTATION) {
            rotation cRot = llList2Rot(hRot,Find);
            vector cPos = llList2Vector(hPos,Find);
            Params = [PRIM_POSITION, rPos+(cPos*rRot), PRIM_ROTATION, (cRot*rRot)/llGetRootRotation()];
            Input = [rPos+(cPos*rRot), cRot*rRot];
        } else if(Operation == PRIM_SIZE) {
            vector cScl = llList2Vector(hScl,Find);
            vector dScl = llList2Vector(Input,5);
            vector tScl = <cScl.x*dScl.x, cScl.y*dScl.y, cScl.z*dScl.z>;
            vector cPos = llList2Vector(hPos,Find);
                   cPos = <cPos.x*dScl.x, cPos.y*dScl.y, cPos.z*dScl.z>;
            Params = [PRIM_POSITION, rPos+(cPos*rRot), PRIM_SIZE, tScl];
            hPos = llListReplaceList(hPos,[cPos],Find,Find);
            hScl = llListReplaceList(hScl,[tScl],Find,Find);
            Input = [rPos+(cPos*rRot),llList2Rot(hRot,Find)*rRot]+llList2List(Input,5,5);
        }
    }
    
    integer PtrA = llList2Integer(hPtrs,(Find*3)+1);
    integer PtrB = llList2Integer(hPtrs,(Find*3)+2);
    integer Children; integer x = 4;
    while(x--) {
        integer ChildA = (PtrA >> (x*8))&0xFF;
        integer ChildB = (PtrB >> (x*8))&0xFF;
        if(ChildA) UpdateTree([Operation,--ChildA,Find]+ Input);
        if(ChildB) UpdateTree([Operation,--ChildB,Find]+ Input);
    }
    llSetLinkPrimitiveParamsFast( llList2Integer(hLink,Find), Params );
}



default {
    state_entry() {
        llOwnerSay("Building Tree..");
        BuildTree();
        llOwnerSay("Updating Tree..");
        vector Pos = <1.5,-.0,-.6>;
        float x;
        for( x = 0; x > -1.0; x -= .1 ) {
            UpdateTree([PRIM_POSITION,"hA",<Pos.x,x,Pos.z>]);
            llSleep(.1);
        }
        
        UpdateTree([PRIM_ROTATION,"hA",llEuler2Rot(<0,0,11.25>*DEG_TO_RAD)]); llSleep( 1.0 );
        
        UpdateTree([PRIM_SIZE,"hA.A",<.5,.6,.3>]); llSleep( 1.0 );
        
        UpdateTree([PRIM_ROTATION,"hA.B.A",llEuler2Rot(<0,0,0>*DEG_TO_RAD)]); llSleep( 1.0 );
        
        UpdateTree([PRIM_ROTATION,"hA",llEuler2Rot(<0,0,0>*DEG_TO_RAD)]); llSleep( 1.0 );
        
        UpdateTree([PRIM_ROTATION,"hA.B.A",llEuler2Rot(<0,11.25,0>*DEG_TO_RAD)]); llSleep( 1.0 );
        
        UpdateTree([PRIM_SIZE,"hA.A",<.5,.5,.5>]); llSleep( 1.0 );
    }
}