*/}}
Browse Source

action retarget support functions

YimingWu 3 months ago
parent
commit
07f39833a5
9 changed files with 87 additions and 18 deletions
  1. 44 10
      la_animation.c
  2. 1 1
      la_data.c
  3. 16 0
      la_data.h
  4. 1 1
      la_kernel.c
  5. 3 0
      la_tns.h
  6. 6 4
      la_tns_kernel.c
  7. 1 1
      resources/la_operators.c
  8. 13 0
      resources/la_properties.c
  9. 2 1
      resources/la_templates.c

+ 44 - 10
la_animation.c

@@ -227,6 +227,40 @@ action_remove_clean:
     memLeave(aa);
 }
 
+void* laAnimationGetRetargetedPropInstance(laProp* p, void* Instance){
+    laPropContainer* pc=p->Container;
+    laProp* rp = la_PropLookup(&pc->Props,"__action_retarget__");
+    if(rp->PropertyType!=LA_PROP_SUB) return Instance;
+    laPropIterator pi={0};
+    void* retargeted = laGetInstance(rp,Instance,&pi);
+    return retargeted;
+}
+void laAnimationEnsureRetarget(void* HolderInstance, laListHandle* action_list, laActionRetarget** retarget){
+    if((*retarget) || (!HolderInstance) || (!action_list)){ return; }
+    int count = lstCountElements(action_list); if(!count){ return; }
+
+    laActionRetarget* ar=memAcquire(sizeof(laActionRetarget));
+    ar->ActionCount = count; ar->Actions = action_list;
+    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);
+        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);
+        }
+    }
+    *retarget = ar;
+}
+void laAnimationClearRetarget(laActionRetarget **ar_ptr){
+    if(!ar_ptr) return;
+    laActionRetarget *ar = *ar_ptr;
+    if(!ar || !ar->ActionCount) return;
+    for(int i=0;i<ar->ActionCount;i++){ memFree(ar->Retargeted[i].Instances); }
+    memFree(ar->Retargeted); memFree(ar); *ar_ptr=0;
+}
+
 int OPCHK_AnimationRemoveAction(laPropPack *This, laStringSplitor *Instructions){
     laPropContainer* pc; return LA_VERIFY_THIS_TYPE(This,pc,"la_animation_action");
 }
@@ -259,16 +293,16 @@ int OPINV_AnimationPlayAction(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 
-void la_AnimationActionSetOwnFrame(laAction* aa, int frame){
+void la_AnimationActionSetOwnFrame(laAction* aa, int frame, int clamp){
     if(!aa) return;
     aa->Offset+=(aa->PlayHead-(real)frame/aa->FrameCount)*aa->Length;
-    la_AnimationEvaluateActions(0);
+    la_AnimationEvaluateActions(clamp);
     laNotifyUsers("la.animation.current_action");
 }
 
 int OPINV_AnimationResetTime(laOperator *a, laEvent *e){
     char* arg=strGetArgumentString(a->ExtraInstructionsP,"current");
-    if(strSame(arg,"true")){ la_AnimationActionSetOwnFrame(MAIN.Animation->CurrentAction,0); return LA_FINISHED; }
+    if(strSame(arg,"true")){ la_AnimationActionSetOwnFrame(MAIN.Animation->CurrentAction,0,1); return LA_FINISHED; }
     laAnimationSetPlayHead(0); la_AnimationEvaluateActions(1);
     return LA_FINISHED;
 }
@@ -302,10 +336,10 @@ void la_AnimationInterpolateKeys(laActionChannel* ac, laActionKey* ak1, laAction
         *data=ak1->Data; break;
     }
 }
-void la_AnimationSetPropValue(laActionProp* ap){
+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=ap->For;
+    PS.p=ap->Prop; PS.Type='.'; PS.UseInstance=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;
@@ -353,10 +387,10 @@ 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<0){ aa->Offset+=aa->Length*2; }
+                while(aa->Offset<-aa->Length*2){ aa->Offset+=aa->Length*2; }
                 preoffset=aa->Offset; postoffset=0;
             }
-            real UseTime=MAIN.Animation->PlayHead-preoffset;
+            real UseTime=MAIN.Animation->PlayHead-preoffset+aa->Length*2;
             int repeats=(real)(UseTime/aa->Length);
             real remaining=UseTime-repeats*aa->Length;
             while(remaining<0){ remaining+=aa->Length; }
@@ -371,7 +405,7 @@ void la_AnimationEvaluateActions(int ClampOffsets){
     for(laActionHolder* ah=MAIN.Animation->ActionHolders.pFirst;ah;ah=ah->Item.pNext){
         if(!ah->Instance){ continue; } laListHandle* lp=((uint8_t*)ah->Instance)+ah->PropOffset;
         for(laActionProp* ap=lp->pFirst;ap;ap=ap->Item.pNext){ if(ap->Reset){ continue; }
-            la_AnimationSetPropValue(ap);
+            la_AnimationSetPropValue(ap,0);
         }
     }
     if(any) laNotifyUsers("la.animation");
@@ -498,7 +532,7 @@ int LAMOD_AnimationActionsCanvas(laOperator *a, laEvent *e){
     }elif(ex->UiMode==3){ Modal=1;
         if(e->type&LA_MOUSE_EVENT){ ex->ClickedX=e->x; ex->ClickedY=e->y;
             int SetFrame=(real)(e->x-tl+ex->PanX)/ex->ZoomX/FW;
-            la_AnimationActionSetOwnFrame(aa,SetFrame);
+            la_AnimationActionSetOwnFrame(aa,SetFrame,0);
         }
     }elif(ex->UiMode==4){ Modal=1;
         if(e->type==LA_R_MOUSE_DOWN || (e->type==LA_ESCAPE_DOWN)){ ex->UiMode=0; ex->Dragging=0;
@@ -530,7 +564,7 @@ int LAMOD_AnimationActionsCanvas(laOperator *a, laEvent *e){
             elif(e->type==LA_MOUSE_WHEEL_UP){ ex->ZoomX*=1.1; ex->PanX+=mid; ex->PanX*=1.1; ex->PanX-=mid; Modal=1; }
             elif(e->type==LA_L_MOUSE_DOWN){
                 ex->UiMode=3; int SetFrame=(real)(e->x-tl+ex->PanX)/ex->ZoomX/FW;
-                la_AnimationActionSetOwnFrame(aa,SetFrame); Modal=1;
+                la_AnimationActionSetOwnFrame(aa,SetFrame,0); Modal=1;
             }elif(e->type==LA_R_MOUSE_DOWN){
                 int row=(e->y-ui->U-bt->BM-LA_RH)/LA_RH; real at=(real)(e->x-tl+ex->PanX)/ex->ZoomX/FW;
                 if(!(e->SpecialKeyBit&LA_KEY_SHIFT)){ la_ActionDeselectFrames(aa); }

+ 1 - 1
la_data.c

@@ -862,7 +862,7 @@ laProp *la_CreateProperty(laPropContainer *Container, int Type, const char *Iden
     p->UDFOnly = (Tag & LA_UDF_ONLY) ? 1 : 0;
     p->ReadOnly = (Tag & LA_READ_ONLY) ? 1 : 0;
     p->IsRadAngle = (Tag & LA_RAD_ANGLE)? 1 : 0;
-    p->UDFHideInSave = (Tag & LA_HIDE_IN_SAVE)? 1 : 0;
+    p->UDFHideInSave = ((Tag & LA_HIDE_IN_SAVE) || p->UDFIgnore)? 1 : 0;
     p->UDFReadProgress = (Tag & LA_PROP_READ_PROGRESS)?1:0;
     p->CanTranslate = (Tag & LA_TRANSLATE)?1:0;
     if(p->IsRadAngle&&(!p->Unit)) p->Unit="°"; 

+ 16 - 0
la_data.h

@@ -674,6 +674,7 @@ STRUCTURE(laAction){
     real PlayHead,Offset;
     int PlayMode;
     int Solo, Mute;
+    int PlayByDefault;
     int MixMode;
 };
 STRUCTURE(laActionProp){
@@ -697,6 +698,17 @@ STRUCTURE(laActionKey){
     int DataSize;
     void* Data;
 };
+STRUCTURE(laRetargetedAction){
+    void** Instances;
+    real PlayHead;
+    int PlayStatus;
+};
+STRUCTURE(laActionRetarget){
+    int ActionCount;
+    real PlaySync;
+    laListHandle* Actions;
+    laRetargetedAction* Retargeted;
+};
 
 #define LA_ACTION_FRAME(aa) (((aa)->PlayHead+FLT_EPSILON)*(real)((aa)->FrameCount))
 
@@ -1042,6 +1054,10 @@ void laAnimationRemoveFrame(laActionChannel* ac, laActionKey* ak);
 void laAnimationRemoveChannel(laAction* aa, laActionChannel* ac);
 void laAnimationRemoveAction(laAction* aa);
 
+void* laAnimationGetRetargetedPropInstance(laProp* p, void* Instance);
+void laAnimationEnsureRetarget(void* HolderInstance, laListHandle* action_list, laActionRetarget** retarget);
+void laAnimationClearRetarget(laActionRetarget **ar_ptr);
+
 void laAnimationSetPlayStatus(int PlayStatus);
 void laAnimationSetPlayHead(real time);
 

+ 1 - 1
la_kernel.c

@@ -1244,7 +1244,7 @@ int laGetReadyWith(laInitArguments* ia){
 
     la_RegenerateWireColors();
 
-    laAnimationRegisterHolderPath("tns.world.root_objects");
+    laAnimationRegisterHolderPath("tns.world.root_objects_as_root");
 
     logPrintNew("Initialization Completed\n");
     MAIN.InitDone=1;

+ 3 - 0
la_tns.h

@@ -610,11 +610,14 @@ STRUCTURE(tnsMaterial){
     real GradientBoxR,GradientBoxF;
 };
 
+NEED_STRUCTURE(laActionRetarget);
+
 STRUCTURE(tnsRootObject){
     tnsObject Base;
 
     laListHandle Actions;
     laListHandle ActionProps;
+    laActionRetarget* ActionRetarget;
 
     tnsObject* ActiveCamera;
     int Is2D;

+ 6 - 4
la_tns_kernel.c

@@ -3927,8 +3927,7 @@ void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
         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;
-        }
-        if(o->Type==TNS_OBJECT_ROOT){ tnsEvaluatedNode* en=ed->Scene->CurrentChild;
+        }elif(o->Type==TNS_OBJECT_ROOT){ tnsEvaluatedNode* en=ed->Scene->CurrentChild;
             tnsRunNode(en,"any",o);
 #ifdef LA_WITH_LUAJIT
             tnsLuaEnsureNode(ed->L,en->LuaID,o);
@@ -4004,12 +4003,15 @@ tnsObject* tnsEnsurePlayDuplicate(tnsObject* o){
         lstAppendPointer(&dup->ChildObjects,co->PlayDuplicate);
         co->PlayDuplicate->ParentObject=o->ParentObject?dup:0; //objects directly under root doesn't have parent object
     }
-    if(o->Type==TNS_OBJECT_INSTANCER){ tnsInstancer* oi=o; tnsEnsurePlayDuplicate(oi->Instance); }
+    if(o->Type==TNS_OBJECT_ROOT){ tnsRootObject* ro=o; laAnimationEnsureRetarget(o,&ro->Actions,&ro->ActionRetarget);
+        ((tnsRootObject*)o->PlayDuplicate)->ActionRetarget=ro->ActionRetarget;
+    }elif(o->Type==TNS_OBJECT_INSTANCER){ tnsInstancer* oi=o; tnsEnsurePlayDuplicate(oi->Instance); }
     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); }
+    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;
 }

+ 1 - 1
resources/la_operators.c

@@ -1779,7 +1779,7 @@ int OPMOD_Panel(laOperator *a, laEvent *e){
     if (!IsTop && !uid->TargetIndexVali){
         laLocalToWindow(0, p, &x, &y);
         dp = laDetectPanel(x, y);
-        if (dp->Mode && dp != p){
+        if (dp && dp->Mode && dp != p){
             return LA_FINISHED;
         }else if ((e->type & LA_MOUSEDOWN) == LA_MOUSEDOWN){
             laPopPanel(p); IsTop=1;

+ 13 - 0
resources/la_properties.c

@@ -990,6 +990,11 @@ laPropContainer* tnsget_ObjectType(tnsObject* o){
     }
 }
 
+tnsObject* tnsget_ObjectRetarget(tnsObject* o, void* unused){
+    if(o && o->PlayDuplicate) return o->PlayDuplicate;
+    return o;
+}
+
 void laget_AnimationActionHolderCategory(void* a_unused, laActionHolder* ah, char* copy, char** ptr){
     if(ah->CategoryTitle&&ah->CategoryTitle->Ptr) *ptr=ah->CategoryTitle->Ptr;
 }
@@ -1167,6 +1172,8 @@ void la_RegisterTNSProps(){
     p = laAddPropertyContainer("tns_world", "World", "3D World Structure", 0,0,sizeof(tnsWorld),tnspost_World,0,1);{
         sp = laAddSubGroup(p, "root_objects", "Root Objects", "List of all root objects", "tns_object",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsWorld, RootObjects), 0);
         laSubGroupDetachable(sp, tnsget_detached_FirstRootObject, laget_ListNext);
+        sp = laAddSubGroup(p, "root_objects_as_root", "Root Objects", "List of all root objects (in type tns_root_object)", "tns_root_object",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsWorld, RootObjects), LA_UDF_IGNORE);
+        laSubGroupDetachable(sp, tnsget_detached_FirstRootObject, laget_ListNext);
         laAddSubGroup(p, "active_root", "Active Root Object", "Global active root object", "tns_object",0,0,0,offsetof(tnsWorld,ActiveRoot),tnsget_detached_FirstRootObject,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
         sp = laAddSubGroup(p, "objects", "Objects", "List of all objects", "tns_object",tnsget_ObjectType, 0,0,-1,0,0,0,0,0,0,offsetof(tnsWorld, AllObjects), 0);
         laSubGroupExtraFunctions(sp,tnsfilter_SavableObject,tnsfilter_SavableObject,0,0,0);
@@ -1221,6 +1228,7 @@ void la_RegisterTNSProps(){
     p = laAddPropertyContainer("tns_object", "Object", "3D Object Item", 0,tnsui_BaseObjectProperties,sizeof(tnsObject), tnspost_Object, 0,2);{
         TNS_PC_OBJECT_GENERIC=p;
         laAddSubGroup(p, "base", "Base", "Object base", "tns_object",0,0,0,-1,laget_Self,0,0,0,0,0,0,LA_UDF_REFER|LA_UDF_IGNORE);
+        laAddSubGroup(p, "__action_retarget__", "Action Retarget", "Get action retargeted instance (play duplicate)", "tns_object",0,0,0,-1,tnsget_ObjectRetarget,0,0,0,0,0,0,LA_UDF_IGNORE);
         laAddStringProperty(p, "name", "Object Name", "The Name Of The Object", 0,0,0,0,1, offsetof(tnsObject, Name), 0,0,0,0,LA_AS_IDENTIFIER);
         laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsObject,Flags),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
         ep = laAddEnumProperty(p, "show", "Show", "Show object in the viewport", 0,0,0,0,0,offsetof(tnsObject, Show), 0,0,0,0,0,0,0,0,0,0);{
@@ -1279,6 +1287,7 @@ void la_RegisterTNSProps(){
             laAddEnumItemAs(ep, "2D", "2D", "Root object is in 2D", 1, 0);
         }
         laAddOperatorProperty(p, "remove_root", "Remove root", "Remove the root node","M_remove_root",L'🗴',0);
+        //laAddSubGroup(p, "as_root_object", "As Root Object", "As root object", "tns_root_object",0,0,0,-1,0,tnsget_ObjectAsRoot,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY|LA_UDF_IGNORE);
     }
     p = laAddPropertyContainer("tns_instancer", "Instancer", "Instance placeholder object", U'📎', tnsui_InstancerObjectProperties,sizeof(tnsInstancer), 0,0,2);{
         laPropContainerExtraFunctions(p,0,0,tnstouched_Object,0/*tnspropagate_Object*/,0);
@@ -2021,6 +2030,10 @@ void la_RegisterInternalProps(){
                 laAddEnumItemAs(ep, "NONE", "None", "Play this action with", 0,0);
                 laAddEnumItemAs(ep, "SOLO", "Solo", "Solo play", 1,0);
             }
+            ep = laAddEnumProperty(p, "play_by_default", "Auto Play", "Automatically play this animation when player starts", 0,0,0,0,0,offsetof(laAction, PlayByDefault),0,0,0,0,0,0,0,0,0,0);{
+                laAddEnumItemAs(ep, "NONE", "Stop", "Player initialize the animation in stopped state", 0,0);
+                laAddEnumItemAs(ep, "PLAY", "Play", "Animation automatically plays when player starts", 1,0);
+            }
             ep = laAddEnumProperty(p, "play_mode", "Play Mode", "How to play this action", 0,0,0,0,0,offsetof(laAction, PlayMode),0,0,0,0,0,0,0,0,0,0);{
                 laAddEnumItemAs(ep, "REPEAT", "Repeat", "Play action in repeat", LA_ANIMATION_PLAY_MODE_REPEAT, U'⮆');
                 laAddEnumItemAs(ep, "HOLD", "Hold", "Hold end values when time is outside time range", LA_ANIMATION_PLAY_MODE_HOLD,U'⭲');

+ 2 - 1
resources/la_templates.c

@@ -1811,9 +1811,10 @@ void laui_AnimationActionChannels(laUiList *uil, laPropPack *This, laPropPack *E
         b=laOnConditionToggle(uil,clr,0,0,0,0,0);{ strSafeSet(&b->ExtraInstructions,"text=☰");
             laShowItem(uil,cl,&ca->PP,"remove");
             row=laBeginRow(uil,cr,0,0);
+            laShowItemFull(uil,cr,&ca->PP,"play_by_default",0,"text=Auto Play;",0,0)->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
             laShowItem(uil,cr,&ca->PP,"mix_mode")->Flags|=LA_UI_FLAGS_EXPAND;
             laShowItem(uil,cr,&ca->PP,"play_mode")->Flags|=LA_UI_FLAGS_EXPAND;
-            laShowSeparator(uil,cr);
+            laShowSeparator(uil,cr)->Expand=1;
             laShowItem(uil,cr,&ca->PP,"solo")->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
             laShowItem(uil,cr,&ca->PP,"mute")->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
             laEndRow(uil,row);