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