Hierarchics2

From Second Life Wiki
Revision as of 07:26, 26 August 2010 by Nexii Malthus (talk | contribs)
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.

<lsl> /*/

       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 );
   }

} </lsl>