*/}}
Browse Source

player instance animation

YimingWu 9 months ago
parent
commit
0064b68e6a
5 changed files with 90 additions and 11 deletions
  1. 61 8
      la_animation.c
  2. 9 1
      la_data.h
  3. 3 0
      la_tns.h
  4. 16 1
      la_tns_kernel.c
  5. 1 1
      resources/la_properties.c

+ 61 - 8
la_animation.c

@@ -138,7 +138,7 @@ laActionKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p, in
         }
     }
     laActionChannel* ac=laAnimationEnsureChannel(aa,hyper1,p); if(!ac || !ac->AP || !ac->AP->For) return;
-    int frame=LA_ACTION_FRAME(aa);
+    int frame=LA_ACTION_FRAME(aa,-1);
     laActionKey* ak=laAnimationEnsureFrame(ac,frame);
     laAnimationStoreKeyValue(ac,ak);
     laNotifyUsers("la.animation.current_action");
@@ -240,12 +240,13 @@ void laAnimationEnsureRetarget(void* HolderInstance, laListHandle* action_list,
     int count = lstCountElements(action_list); if(!count){ return; }
 
     laActionRetarget* ar=memAcquire(sizeof(laActionRetarget));
-    ar->ActionCount = count; ar->Actions = action_list;
+    ar->ActionCount = count; ar->Actions = action_list; ar->HolderInstance = HolderInstance;
     ar->Retargeted = memAcquireSimple(sizeof(laRetargetedAction)*count);
     int i=0;
     for(laAction* aa=action_list->pFirst;aa;aa=aa->Item.pNext){
         int channels = lstCountElements(&aa->Channels);
         ar->Retargeted[i].Instances = memAcquireSimple(sizeof(void*)*channels);
+        ar->Retargeted[i].PlayStatus = aa->PlayByDefault?LA_ANIMATION_STATUS_PLAY_FWD:0;
         int j=0;
         for(laActionChannel* ac = aa->Channels.pFirst;ac;ac=ac->Item.pNext){
             ar->Retargeted[i].Instances[j] = laAnimationGetRetargetedPropInstance(ac->AP->Prop,ac->AP->For);
@@ -253,6 +254,12 @@ void laAnimationEnsureRetarget(void* HolderInstance, laListHandle* action_list,
     }
     *retarget = ar;
 }
+laActionRetarget* laAnimationCopyRetargetFrom(laActionRetarget* from_ar){
+    if(!from_ar) return 0;
+    laActionRetarget* ar=0;
+    laAnimationEnsureRetarget(from_ar->HolderInstance, from_ar->Actions, &ar);
+    return ar;
+}
 void laAnimationClearRetarget(laActionRetarget **ar_ptr){
     if(!ar_ptr) return;
     laActionRetarget *ar = *ar_ptr;
@@ -260,6 +267,9 @@ void laAnimationClearRetarget(laActionRetarget **ar_ptr){
     for(int i=0;i<ar->ActionCount;i++){ memFree(ar->Retargeted[i].Instances); }
     memFree(ar->Retargeted); memFree(ar); *ar_ptr=0;
 }
+void laSetRunPlayHead(real RunPlayHead){
+    MAIN.Animation->RunPlayHead = RunPlayHead;
+}
 
 int OPCHK_AnimationRemoveAction(laPropPack *This, laStringSplitor *Instructions){
     laPropContainer* pc; return LA_VERIFY_THIS_TYPE(This,pc,"la_animation_action");
@@ -339,7 +349,7 @@ void la_AnimationInterpolateKeys(laActionChannel* ac, laActionKey* ak1, laAction
 void la_AnimationSetPropValue(laActionProp* ap, void* OverrideInstance){
     void* data=ap->Data;
     laPropPack PP={0}; laPropStep PS={0}; if(!ap) return;
-    PS.p=ap->Prop; PS.Type='.'; PS.UseInstance=ap->For; PP.LastPs=&PS; PP.EndInstance=OverrideInstance?OverrideInstance:ap->For;
+    PS.p=ap->Prop; PS.Type='.'; PS.UseInstance=OverrideInstance?OverrideInstance:ap->For; PP.LastPs=&PS; PP.EndInstance=OverrideInstance?OverrideInstance:ap->For;
     switch(ap->Prop->PropertyType){
     case LA_PROP_INT: laSetInt(&PP,*((int*)data)); break;
     case LA_PROP_INT|LA_PROP_ARRAY: laSetIntArrayAllArray(&PP,(int*)data); break;
@@ -366,9 +376,9 @@ void la_AnimationMixChannelValue(laActionChannel* ac, void* data, int MixMode, r
     }
     ap->Reset=0;
 }
-void la_AnimationEvaluateActionChannels(laAction* aa){
+void la_AnimationEvaluateActionChannels(laAction* aa, real OverridePlayHead){
     int64_t _data[16]; void* data=_data;
-    int frame=LA_ACTION_FRAME(aa); real totframe=aa->PlayHead*aa->FrameCount;
+    int frame=LA_ACTION_FRAME(aa,OverridePlayHead); real totframe=((OverridePlayHead>=0)?OverridePlayHead:aa->PlayHead)*aa->FrameCount;
     for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
         data=_data;
         laActionKey* ak1=laAnimationGetFrame(ac,frame); if(!ak1) continue;
@@ -387,7 +397,7 @@ void la_AnimationEvaluateActions(int ClampOffsets){
             real preoffset=0,postoffset=aa->Offset/aa->Length;
             if(ClampOffsets || (MAIN.Animation->PlayStatus!=LA_ANIMATION_STATUS_PAUSED)){
                 while(aa->Offset>aa->Length*2){ aa->Offset-=aa->Length*2; }
-                while(aa->Offset<-aa->Length*2){ aa->Offset+=aa->Length*2; }
+                while(aa->Offset<0){ aa->Offset+=aa->Length*2; }
                 preoffset=aa->Offset; postoffset=0;
             }
             real UseTime=MAIN.Animation->PlayHead-preoffset+aa->Length*2;
@@ -398,7 +408,7 @@ void la_AnimationEvaluateActions(int ClampOffsets){
             elif(aa->PlayMode==LA_ANIMATION_PLAY_MODE_HOLD){ aa->PlayHead=((UseTime>aa->Length)?1.0:(UseTime<0?0:UseTime/aa->Length))-postoffset; }
             elif(aa->PlayMode==LA_ANIMATION_PLAY_MODE_BOUNCE){ real t=remaining/aa->Length; aa->PlayHead=((repeats%2)?(1-t):t)-postoffset; }
             any=1;
-            la_AnimationEvaluateActionChannels(aa);
+            la_AnimationEvaluateActionChannels(aa,-1);
         }
     }
     
@@ -410,6 +420,49 @@ void la_AnimationEvaluateActions(int ClampOffsets){
     }
     if(any) laNotifyUsers("la.animation");
 }
+void la_AnimationMarkRetargetedReset(laActionRetarget* ar){
+    for(laAction* aa=ar->Actions->pFirst;aa;aa=aa->Item.pNext){
+        for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
+            if(ac->AP) ac->AP->Reset = 1;
+        }
+    }
+}
+int laAnimationSyncRetarget(laActionRetarget* ar, real PlayHead){
+    if(ar->PlaySync == PlayHead) return 0;
+    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;
+        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){
+            if(ar->Retargeted[i].PlayHead<0){ ar->Retargeted[i].PlayHead=-ar->Retargeted[i].PlayHead; ar->Retargeted[i].Direction = 1; }
+            elif(ar->Retargeted[i].PlayHead>1.0f){ ar->Retargeted[i].PlayHead=1.0f-(ar->Retargeted[i].PlayHead-1.0f); ar->Retargeted[i].Direction = -1; }
+        }
+        i++;
+    }
+    return 1;
+}
+int laAnimationEvaluateRetargetedActions(laActionRetarget* ar){
+    int any=0; if(!ar || !ar->Retargeted){ return 0; }
+
+    la_AnimationMarkRetargetedReset(ar); int i=0;
+    for(laAction* aa=ar->Actions->pFirst;aa;aa=aa->Item.pNext){
+        la_AnimationEvaluateActionChannels(aa,ar->Retargeted[i].PlayHead);
+        i++;
+    }
+    
+    i=0; int j=0;
+    for(laAction* aa=ar->Actions->pFirst;aa;aa=aa->Item.pNext){
+        for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
+            if(ac->AP->Reset){ j++; continue; }
+            la_AnimationSetPropValue(ac->AP,ar->Retargeted[i].Instances[j]);
+            j++; any=1;
+        }
+        i++;
+    }
+    return any;
+}
 
 void la_AnimationPreFrame(){
     if(MAIN.Animation->PlayHead<0){
@@ -633,7 +686,7 @@ void la_AnimationActionDrawCanvas(laBoxedTheme *bt, laAction *aa, laUiItem* ui){
     la_DoUiScissor(ui,&sx,&sy,&sw,&sh,&vl,&vr,&vu,&vb);
 
     if(aa){
-        curframe=LA_ACTION_FRAME(aa); fl=tl+curframe*FW*ex->ZoomX-ex->PanX, fr=tl+(curframe+1)*FW*ex->ZoomX-ex->PanX;
+        curframe=LA_ACTION_FRAME(aa,-1); fl=tl+curframe*FW*ex->ZoomX-ex->PanX, fr=tl+(curframe+1)*FW*ex->ZoomX-ex->PanX;
         tnsUseNoTexture();
         tnsColor4dv(laAccentColor(LA_BT_NORMAL));
         tnsVertex2d(fl, ui->U); tnsVertex2d(fr, ui->U);

+ 9 - 1
la_data.h

@@ -663,6 +663,8 @@ STRUCTURE(laAnimation){
     real PlayHead;
     int PlayStatus;
     laTimeRecorder TimeOrigin;
+
+    real RunPlayHead;
 };
 STRUCTURE(laAction){
     laListItem Item;
@@ -702,15 +704,17 @@ STRUCTURE(laRetargetedAction){
     void** Instances;
     real PlayHead;
     int PlayStatus;
+    int Direction;
 };
 STRUCTURE(laActionRetarget){
     int ActionCount;
     real PlaySync;
     laListHandle* Actions;
     laRetargetedAction* Retargeted;
+    void* HolderInstance;
 };
 
-#define LA_ACTION_FRAME(aa) (((aa)->PlayHead+FLT_EPSILON)*(real)((aa)->FrameCount))
+#define LA_ACTION_FRAME(aa,override_playhead) (((((override_playhead)>=0)?(override_playhead):(aa)->PlayHead)+FLT_EPSILON)*(real)((aa)->FrameCount))
 
 /* Only little endian are supported right now */
 #define LA_UDF_IDENTIFIER "UDF_LE"
@@ -1056,11 +1060,15 @@ void laAnimationRemoveAction(laAction* aa);
 
 void* laAnimationGetRetargetedPropInstance(laProp* p, void* Instance);
 void laAnimationEnsureRetarget(void* HolderInstance, laListHandle* action_list, laActionRetarget** retarget);
+laActionRetarget* laAnimationCopyRetargetFrom(laActionRetarget* from_ar);
 void laAnimationClearRetarget(laActionRetarget **ar_ptr);
 
 void laAnimationSetPlayStatus(int PlayStatus);
 void laAnimationSetPlayHead(real time);
 
+int laAnimationSyncRetarget(laActionRetarget* ar, real PlayHead);
+int laAnimationEvaluateRetargetedActions(laActionRetarget* ar);
+
 void la_AnimationPreFrame();
 void la_AnimationPostFrame();
 

+ 3 - 0
la_tns.h

@@ -484,10 +484,13 @@ NEED_STRUCTURE(tnsBatch)
 NEED_STRUCTURE(tnsEvaluatedInstance);
 typedef void (*tnsDrawEvaluatedInstanceF)(tnsEvaluatedInstance* ei, void* CustomData);
 
+NEED_STRUCTURE(laActionRetarget);
+
 STRUCTURE(tnsEvaluatedNode){
     laListItem Item;
     tnsMatrix44d Mat;
     tnsObject* Target;
+    laActionRetarget* ActionRetarget;
     laListHandle Children;
     int LuaID, LuaLoaded;
 };

+ 16 - 1
la_tns_kernel.c

@@ -3924,7 +3924,13 @@ void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
     tnsEvaluatedNode* CP,*CC;
     if(ed->SceneEvaluateMode){
         tnsEvaluateSyncNode(ed,o);
-        if(o->Type==TNS_OBJECT_INSTANCER){
+        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){
             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;
@@ -4166,6 +4172,9 @@ tnsEvaluatedNode* tnsAcquireEvaluateNode(tnsEvaluateData* ed){
 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);
+    }
     tnsMultiply44d(en->Mat,ed->MatArr[ed->NextMat-1],ob->GlobalTransform);
     if(s->CurrentChild) lstInsertItemBefore(&s->CurrentParent->Children,en,s->CurrentChild);
     else lstAppendItem(&s->CurrentParent->Children,en);
@@ -4183,6 +4192,9 @@ int tnsEvaluateTryRelinkExistingNode(tnsEvaluateData* ed, tnsObject* ob){
 void tnsEvaluateEndNode(tnsEvaluateData* ed, tnsEvaluatedNode* en){
     tnsEvaluatedNode* sen;
     while(sen=lstPopItem(&en->Children)){ tnsEvaluateEndNode(ed,sen); }
+    if(en->Target->Type==TNS_OBJECT_ROOT){ tnsRootObject* ro=en->Target;
+        laAnimationClearRetarget(&en->ActionRetarget);
+    }
     int luaid=en->LuaID; memset(en,0,sizeof(tnsEvaluatedNode)); //memFree(sen);
     en->LuaID=luaid;
 #ifdef LA_WITH_LUAJIT
@@ -4215,6 +4227,9 @@ void tnsEnsureEvaluatedScene(tnsEvaluateData* ed, tnsObject* root){
     if(!ed->Scene->Root){ 
         ed->Scene->Root=tnsAcquireEvaluateNode(ed);
         ed->Scene->NextLuaID++; ed->Scene->Root->LuaID=ed->Scene->NextLuaID;
+        if(root->Type==TNS_OBJECT_ROOT){ tnsRootObject* ro=root;
+            ed->Scene->Root->ActionRetarget=laAnimationCopyRetargetFrom(ro->ActionRetarget);
+        }
     }
     ed->Scene->CurrentChild=ed->Scene->Root;
     ed->Scene->CurrentChild->Target=root; tnsLoadIdentity44d(ed->Scene->CurrentChild->Mat);

+ 1 - 1
resources/la_properties.c

@@ -999,7 +999,7 @@ void laget_AnimationActionHolderCategory(void* a_unused, laActionHolder* ah, cha
     if(ah->CategoryTitle&&ah->CategoryTitle->Ptr) *ptr=ah->CategoryTitle->Ptr;
 }
 int laget_AnimationActionCurrentFrame(laAction* aa){
-    return LA_ACTION_FRAME(aa);
+    return LA_ACTION_FRAME(aa,-1);
 }
 void laget_AnimationPropStr(laActionProp* ap, char* str, char** here){
     sprintf(str,"%s.%s",ap->Prop->Container->Identifier,ap->Prop->Identifier);