*/}}
Browse Source

Baseic animation node

YimingWu 9 months ago
parent
commit
bb7f94ac37
6 changed files with 132 additions and 24 deletions
  1. 9 4
      la_animation.c
  2. 2 0
      la_data.h
  3. 1 1
      la_kernel.c
  4. 14 1
      la_tns.h
  5. 14 17
      la_tns_kernel.c
  6. 92 1
      resources/la_tns_drivers.c

+ 9 - 4
la_animation.c

@@ -427,12 +427,17 @@ void la_AnimationMarkRetargetedReset(laActionRetarget* ar){
         }
     }
 }
+laRetargetedAction* la_AnimationGetRetargetedAction(laActionRetarget* ar, laAction* aa){
+    int i=0; for(laAction* a=ar->Actions->pFirst;a&&i<ar->ActionCount;a=a->Item.pNext){ if(a==aa) return &ar->Retargeted[i]; }
+}
 int laAnimationSyncRetarget(laActionRetarget* ar, real PlayHead){
-    if(ar->PlaySync == PlayHead) return 0;
+    int need_sync = (ar->PlaySync != PlayHead);
     real delta = PlayHead-ar->PlaySync; ar->PlaySync = PlayHead; int i=0;
-    for(laAction* aa=ar->Actions->pFirst;aa;aa=aa->Item.pNext){ if(!ar->Retargeted[i].PlayStatus){ i++; continue; }
-        int fac_direction = ((ar->Retargeted[i].Direction<0)?-1:1);
-        ar->Retargeted[i].PlayHead += delta / aa->Length * fac_direction;
+    for(laAction* aa=ar->Actions->pFirst;aa;aa=aa->Item.pNext){
+        if(ar->Retargeted[i].PlayStatus && need_sync){
+            int fac_direction = ((ar->Retargeted[i].Direction<0)?-1:1);
+            ar->Retargeted[i].PlayHead += delta / aa->Length * fac_direction;
+        }
         if(aa->PlayMode==LA_ANIMATION_PLAY_MODE_REPEAT){ ar->Retargeted[i].Direction = 1;ar->Retargeted[i].PlayHead=fmod(ar->Retargeted[i].PlayHead,1.0f); }
         elif(aa->PlayMode==LA_ANIMATION_PLAY_MODE_HOLD){ ar->Retargeted[i].Direction = 1; TNS_CLAMP(ar->Retargeted[i].PlayHead,0.0f,1.0f); }
         elif(aa->PlayMode==LA_ANIMATION_PLAY_MODE_BOUNCE){

+ 2 - 0
la_data.h

@@ -707,6 +707,7 @@ STRUCTURE(laRetargetedAction){
     int Direction;
 };
 STRUCTURE(laActionRetarget){
+    int DetachedInNode;
     int ActionCount;
     real PlaySync;
     laListHandle* Actions;
@@ -1047,6 +1048,7 @@ void laRedo();
 int la_GetKeyablePropertyStorageSize(laProp* p);
 
 void la_AnimationEvaluateActions(int ClampOffsets);
+laRetargetedAction* la_AnimationGetRetargetedAction(laActionRetarget* ar, laAction* aa);
 
 laAction* laAnimiationNewAction(laActionHolder* ah, char* Name);
 laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p);

+ 1 - 1
la_kernel.c

@@ -920,7 +920,7 @@ void laProcessInitArguments(int argc, char* argv[],laInitArguments* ia) {
 }
 int laGetReadyWith(laInitArguments* ia){
 #ifdef __linux__
-    signal(SIGSEGV,la_HandlerSIGSEGV);
+    //signal(SIGSEGV,la_HandlerSIGSEGV);
 #endif
 
     memcpy(&MAIN.InitArgs,ia,sizeof(laInitArguments));

+ 14 - 1
la_tns.h

@@ -174,6 +174,7 @@ struct _tnsWorld
 NEED_STRUCTURE(tnsLoopItem);
 NEED_STRUCTURE(tnsRenderLine);
 NEED_STRUCTURE(tnsRenderBuffer);
+NEED_STRUCTURE(tnsEvaluatedNode);
 
 STRUCTURE(tnsImage){
     laListItem Item;
@@ -292,6 +293,10 @@ struct _tnsMain {
     tnsRenderBuffer *ActiveRenderBuffer;
 
     laListHandle Images;
+
+    struct Runtime{
+        tnsEvaluatedNode* CurrentEN;
+    }Runtime;
 };
 
 typedef struct _tnsTexture tnsTexture;
@@ -576,6 +581,7 @@ STRUCTURE(tnsObject){
 
 NEED_STRUCTURE(laNodeInSocket);
 NEED_STRUCTURE(laNodeOutSocket);
+NEED_STRUCTURE(laAction);
 
 STRUCTURE(tnsTransformNode){
     laBaseNode Base;
@@ -588,6 +594,14 @@ STRUCTURE(tnsMakeTransformNode){
     laNodeOutSocket* Out;
     tnsMatrix44d Mat; tnsVector3d UseLoc; tnsVector3d UseRot; real UseSca; real UseAngle;
 };
+STRUCTURE(tnsActionPlayerNode){
+    laBaseNode Base;
+    laNodeInSocket* Prev; laNodeOutSocket* Next;
+    laNodeInSocket* Transport; int iTransport;
+    laNodeInSocket* Time;
+    laNodeInSocket* Detached; int iDetached;
+    laAction* Action;
+};
 
 #define TNS_CAMERA_PERSP 0
 #define TNS_CAMERA_ORTHO 1
@@ -1278,7 +1292,6 @@ void tnsApplyModelMatrix(tnsMatrix44d m);
 void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up);
 
 tnsObject* tnsEnsurePlayDuplicate(tnsObject* o);
-void tnsFreePlayDuplicate(tnsObject* o);
 
 void tnsInvalidateEvaluation(tnsObject* o);
 void tnsInvalidatePlayEvaluation(tnsObject* o);

+ 14 - 17
la_tns_kernel.c

@@ -3909,6 +3909,7 @@ eval_inst_cleanup:
 }
 
 void tnsRunNode(tnsEvaluatedNode* en, char* func, tnsObject* root){
+    T->Runtime.CurrentEN = en;
     tnsObject* ob=root; // should be the same as en->Target.
     for(laRackPage* rp=ob->Drivers->Pages.pFirst;rp;rp=rp->Item.pNext){
         if(!rp->Eval.pFirst) continue;
@@ -3924,13 +3925,7 @@ void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
     tnsEvaluatedNode* CP,*CC;
     if(ed->SceneEvaluateMode){
         tnsEvaluateSyncNode(ed,o);
-        if(o->Type==TNS_OBJECT_ROOT){
-            tnsEvaluatedNode* en=ed->Scene->CurrentChild;
-            if(en->ActionRetarget){
-                laAnimationSyncRetarget(en->ActionRetarget, MAIN.Animation->RunPlayHead);
-                laAnimationEvaluateRetargetedActions(en->ActionRetarget);
-            }
-        }elif(o->Type==TNS_OBJECT_INSTANCER){
+        if(o->Type==TNS_OBJECT_INSTANCER){
             CP=ed->Scene->CurrentParent; CC=ed->Scene->CurrentChild;
             ed->Scene->CurrentParent=ed->Scene->CurrentChild; ed->Scene->CurrentChild=ed->Scene->CurrentParent->Children.pFirst;
         }elif(o->Type==TNS_OBJECT_ROOT){ tnsEvaluatedNode* en=ed->Scene->CurrentChild;
@@ -3939,6 +3934,13 @@ void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
             tnsLuaEnsureNode(ed->L,en->LuaID,o);
             tnsLuaRunNode(ed->L,en,"run",o);
 #endif
+            if(en->ActionRetarget){
+                laActionRetarget* ar;
+                if(en->ActionRetarget->DetachedInNode){ ar = en->ActionRetarget; }
+                else{ ar = ((tnsRootObject*)en->Target)->ActionRetarget; }
+                laAnimationSyncRetarget(ar, MAIN.Animation->RunPlayHead);
+                laAnimationEvaluateRetargetedActions(ar);
+            }
         }
     }
     if (!o->Show) return;
@@ -3967,20 +3969,21 @@ void tnsClearPlayDuplicate(tnsObject* o){
     for(laListItemPointer* lip=o->ChildObjects.pFirst;lip;lip=lip->pNext){
         tnsObject*co=lip->p; tnsClearPlayDuplicate(co);
     }
-    if(o->Type==TNS_OBJECT_INSTANCER){ tnsInstancer* oi=o; tnsClearPlayDuplicate(oi->Instance); }
+    if(o->Type==TNS_OBJECT_ROOT){ tnsRootObject* ro=o; laAnimationClearRetarget(&ro->ActionRetarget); }
+    elif(o->Type==TNS_OBJECT_INSTANCER){ tnsInstancer* oi=o; tnsClearPlayDuplicate(oi->Instance); }
     memFree(o->PlayDuplicate); o->PlayDuplicate=0;
 }
 void tnsFreeEvaluatedNode(tnsEvaluatedNode* n){
     tnsEvaluatedNode* en;
     while(en=lstPopItem(&n->Children)){ tnsFreeEvaluatedNode(en); }
-    n->Target->LuaCacheID=0;
+    n->Target->LuaCacheID=0; laAnimationClearRetarget(&n->ActionRetarget);
     memFree(n);
 }
 void tnsFreeEvaluatedScene(tnsEvaluateData* ed){
     if(!ed->Scene) return;
     if(ed->Scene->Root) tnsFreeEvaluatedNode(ed->Scene->Root);
-    logPrintNew("Shutting down Lua for the evaluated scene.\n");
 #ifdef LA_WITH_LUAJIT
+    logPrintNew("Shutting down Lua for the evaluated scene.\n");
     lua_close(ed->L);
 #endif
     memFree(ed->Scene); ed->Scene=0;
@@ -4015,12 +4018,6 @@ tnsObject* tnsEnsurePlayDuplicate(tnsObject* o){
     dup->Flags|=TNS_OBJECT_FLAGS_PLAY_DUPLICATE;
     return o->PlayDuplicate;
 }
-void tnsFreePlayDuplicate(tnsObject* o){
-    for(laListItemPointer* lip=o->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsFreePlayDuplicate(lip->p); }
-    if(o->Type==TNS_OBJECT_ROOT){ tnsRootObject* ro=o; laAnimationClearRetarget(&ro->ActionRetarget); }
-    memFree(o->PlayDuplicate);
-    o->PlayDuplicate=0;
-}
 
 #ifdef LA_WITH_LUAJIT
 
@@ -4173,7 +4170,7 @@ void tnsEvaluateNewNode(tnsEvaluateData* ed, tnsObject* ob){
     tnsEvaluatedScene* s=ed->Scene;
     tnsEvaluatedNode* en=tnsAcquireEvaluateNode(ed); en->Target=ob;
     if(ob->Type==TNS_OBJECT_ROOT){ tnsRootObject* ro=ob;
-        en->ActionRetarget=laAnimationCopyRetargetFrom(ro->ActionRetarget);
+        en->ActionRetarget=laAnimationCopyRetargetFrom(ro->ActionRetarget); en->ActionRetarget->DetachedInNode = 1;
     }
     tnsMultiply44d(en->Mat,ed->MatArr[ed->NextMat-1],ob->GlobalTransform);
     if(s->CurrentChild) lstInsertItemBefore(&s->CurrentParent->Children,en,s->CurrentChild);

+ 92 - 1
resources/la_tns_drivers.c

@@ -23,9 +23,11 @@ extern struct _tnsMain *T;
 
 laBaseNodeType TNS_IDN_TRANSFORM;
 laBaseNodeType TNS_IDN_MAKE_TRANSFORM;
+laBaseNodeType TNS_IDN_ACTION_PLAYER;
 
 laPropContainer* TNS_PC_IDN_TRANSFORM;
 laPropContainer* TNS_PC_IDN_MAKE_TRANSFORM;
+laPropContainer* TNS_PC_IDN_ACTION_PLAYER;
 
 void IDN_TransformInit(tnsTransformNode* n, int NoCreate){
     if(NoCreate){return;}
@@ -141,6 +143,74 @@ void tnsui_MakeTransformNode(laUiList *uil, laPropPack *This, laPropPack *Extra,
     laEndRow(uil,b);
 }
 
+
+void IDN_ActionPlayerInit(tnsActionPlayerNode* n, int NoCreate){
+    if(NoCreate){ return; }
+    strSafeSet(&n->Base.Name,"Make Transform");
+    n->Next=laCreateOutSocket(n,"NEXT",0); n->Prev=laCreateInSocket("PREV",0);
+    n->Transport=laCreateInSocket("TRANSPORT",0); n->Detached=laCreateInSocket("DETACHED",0); n->Time=laCreateInSocket("TIME",0);
+}
+void IDN_ActionPlayerDestroy(tnsActionPlayerNode* n){
+    laDestroyInSocket(n->Prev); laDestroyOutSocket(n->Next); strSafeDestroy(&n->Base.Name);
+    laDestroyInSocket(n->Transport); laDestroyInSocket(n->Time); laDestroyInSocket(n->Detached);
+}
+int IDN_ActionPlayerVisit(tnsActionPlayerNode* n, laNodeVisitInfo* vi){
+    LA_GUARD_THIS_NODE(n,vi);
+    if(LA_SRC_AND_PARENT(n->Prev)){ laBaseNode*bn=n->Prev->Source->Parent; LA_VISIT_NODE(bn,vi); }
+    LA_ADD_THIS_NODE(n,vi);
+    return LA_DAG_FLAG_PERM;
+}
+int IDN_ActionPlayerEval(tnsActionPlayerNode* n){
+    if(!T->Runtime.CurrentEN || !n->Action){ return 1; } tnsEvaluatedNode* en=T->Runtime.CurrentEN;
+    int transport = n->iTransport; LA_GET_SRC_AS_VALUE(transport,n->Transport);
+    int detached = n->iDetached; LA_GET_SRC_AS_VALUE(detached,n->Detached);
+    real time = 0; int has_time=n->Time->Source?1:0; LA_GET_SRC_AS_VALUE(time,n->Time);
+    if(en->ActionRetarget){
+        laActionRetarget* ar=en->ActionRetarget;
+        en->ActionRetarget->DetachedInNode = detached;
+        if(!en->ActionRetarget->DetachedInNode){ ar=((tnsRootObject*)en->Target)->ActionRetarget; }
+        laRetargetedAction* ra=la_AnimationGetRetargetedAction(ar,n->Action); if(!ra){ return 1; }
+        ra->PlayStatus = transport; if(has_time){ ra->PlayHead = time; }
+    }else{
+        tnsRootObject* o=en->Target; if(o->Base.Type!=TNS_OBJECT_ROOT){ return 1; }
+        if(has_time){ n->Action->Offset=0; n->Action->PlayHead=time; }
+    }
+    return 1;
+}
+void IDN_ActionPlayerCopy(tnsActionPlayerNode* new, tnsActionPlayerNode* old, int DoRematch){
+    if(DoRematch){ LA_IDN_NEW_LINK(Prev) return; }
+    old->Next->Duplicated=new->Next; new->Time=old->Time; new->Transport=old->Transport; new->Detached=old->Detached;
+    new->iDetached = old->iDetached; new->iTransport = old->iTransport;
+}
+void tnsui_ActionPlayerNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil),*cl,*cr,*cll,*clr;
+    LA_BASE_NODE_HEADER(uil,c,This);
+    laSplitColumn(uil,c,0.6); cl=laLeftColumn(c,0); cr=laRightColumn(c,3);
+    laSplitColumn(uil,cl,0.4); cll=laLeftColumn(cl,3); clr=laRightColumn(cl,0);
+    tnsActionPlayerNode*n=This->EndInstance;
+    laUiItem* b2, *rui;
+
+    laShowNodeSocket(uil,cr,This,"prev",0)->Flags|=LA_UI_SOCKET_LABEL_W;
+    laShowNodeSocket(uil,cr,This,"next",0)->Flags|=LA_UI_SOCKET_LABEL_W;
+
+    laUiItem* b=laBeginRow(uil,cl,0,0);
+    laShowNodeSocket(uil,cl,This,"in_transport",0); b2=laOnConditionThat(uil,c,laNot(laPropExpression(This,"in_transport.source")));{
+        laShowItemFull(uil,cl,This,"transport",0,"text=Transport",0,0)->Expand=1;
+    }laElse(uil,b2);{
+        laShowLabel(uil,cl,"Transport",0,0)->Expand=1;
+    }laEndCondition(uil,b2);
+    laShowNodeSocket(uil,cl,This,"in_detached",0); b2=laOnConditionThat(uil,c,laNot(laPropExpression(This,"in_detached.source")));{
+        laShowItemFull(uil,cl,This,"detached",0,"text=Detached",0,0)->Expand=1;
+    }laElse(uil,b2);{
+        laShowLabel(uil,cl,"Detached",0,0)->Expand=1;
+    }laEndCondition(uil,b2);
+    laEndRow(uil,b);
+
+    laShowNodeSocket(uil,cll,This,"in_time",0)->Flags|=LA_UI_SOCKET_LABEL_E;
+    laShowItemFull(uil,clr,This,"action",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+}
+
+
 int OPCHK_AddDriverPage(laPropPack *This, laStringSplitor *ss){
     if (This && la_EnsureSubTarget(This->LastPs->p,0) == TNS_PC_OBJECT_GENERIC) return 1;
     return 0;
@@ -192,6 +262,10 @@ int OPINV_RebuildDrivers(laOperator* a, laEvent *e){
 tnsObject* tnsget_FirstObject(void* unused, void* unused2){
     return T->World->AllObjects.pFirst;
 }
+laAction* tnsget_FirstActionFromActionPlayer(tnsActionPlayerNode* apn, void* unused2){
+    if(!apn->Base.InRack || !apn->Base.InRack->ParentPage || !apn->Base.InRack->ParentPage->ParentObject) return 0;
+    tnsRootObject* ro = apn->Base.InRack->ParentPage->ParentObject; return ro->Actions.pFirst;
+}
 
 void tns_RegisterNodes(){
     laPropContainer *pc; laProp *p;
@@ -225,11 +299,28 @@ void tns_RegisterNodes(){
     laAddFloatProperty(pc,"use_rot", "Rotation", "Use Rotation",0,"X,Y,Z",0,0,0,0.05,0,0,offsetof(tnsMakeTransformNode, UseRot),0,0,3,0,0,0,0,0,0,0,0);
     laAddFloatProperty(pc,"use_sca", "Scale", "Use Scale",0,0,0,0,0,0.05,0,0,offsetof(tnsMakeTransformNode, UseSca),0,0,0,0,0,0,0,0,0,0,0);
     laAddFloatProperty(pc,"use_angle", "Angle", "Use Angle",0,0,0,0,0,0.05,0,0,offsetof(tnsMakeTransformNode, UseAngle),0,0,0,0,0,0,0,0,0,0,0);
+
+    pc=laAddPropertyContainer("tns_action_player_node", "Action Player", "Action player node",0,tnsui_ActionPlayerNode,sizeof(tnsActionPlayerNode),lapost_Node,0,1);
+    TNS_PC_IDN_ACTION_PLAYER=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
+    laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
+    laAddSubGroup(pc,"prev", "Previous","Previous node","la_in_socket",0,0,0,offsetof(tnsActionPlayerNode,Prev),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"next", "Next","Next node","la_out_socket",0,0,0,offsetof(tnsActionPlayerNode,Next),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"in_transport", "In Transport","Transport input","la_in_socket",0,0,0,offsetof(tnsActionPlayerNode,Transport),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"in_time", "In Time","Time Input","la_in_socket",0,0,0,offsetof(tnsActionPlayerNode,Time),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"in_detached", "In Detached","Detached input","la_in_socket",0,0,0,offsetof(tnsActionPlayerNode,Detached),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    ep=laAddEnumProperty(pc,"transport","Transport","Action in transport",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(tnsActionPlayerNode,iTransport),0,0,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(ep,"STOPPED","Stopped","Player is stopped",0,0);
+    laAddEnumItemAs(ep,"PLAYING","Playing","Player is playing",1,0);
+    ep=laAddEnumProperty(pc,"detached","Detached","Action is detached on the instance",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(tnsActionPlayerNode,iDetached),0,0,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(ep,"NONE","None","Action is reused from instancer",0,0);
+    laAddEnumItemAs(ep,"DETACHED","Detached","Action state is on instance itself",1,0);
+    laAddSubGroup(pc,"action","Action","Target action","la_animation_action",0,0,0,offsetof(tnsActionPlayerNode,Action),tnsget_FirstActionFromActionPlayer,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
     
     LA_IDN_REGISTER("Transform",0,TNS_IDN_TRANSFORM,TNS_PC_IDN_TRANSFORM, IDN_Transform, tnsTransformNode);
     LA_IDN_REGISTER("Make Transform",0,TNS_IDN_MAKE_TRANSFORM,TNS_PC_IDN_MAKE_TRANSFORM, IDN_MakeTransform, tnsMakeTransformNode);
+    LA_IDN_REGISTER("Action Player",0,TNS_IDN_ACTION_PLAYER,TNS_PC_IDN_ACTION_PLAYER, IDN_ActionPlayer, tnsActionPlayerNode);
 
     laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_MATH, &TNS_IDN_MAKE_TRANSFORM,0);
-    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_DRIVER, &TNS_IDN_TRANSFORM,0);
+    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_DRIVER, &TNS_IDN_TRANSFORM, &TNS_IDN_ACTION_PLAYER,0);
 }