|
@@ -21,30 +21,37 @@
|
|
|
extern LA MAIN;
|
|
|
|
|
|
int la_GetKeyablePropertyStorageSize(laProp* p);
|
|
|
+void la_AnimationEvaluateActions(int ClampOffsets);
|
|
|
|
|
|
laAction* laAnimiationNewAction(char* Name){
|
|
|
laAction* aa=memAcquire(sizeof(laAction));
|
|
|
if(!Name || !Name[0]){ Name="New Action"; }
|
|
|
strSafeSet(&aa->Name,Name);
|
|
|
- aa->Length=5; aa->FrameCount=120;
|
|
|
+ aa->Length=2; aa->FrameCount=24;
|
|
|
memAssignRef(MAIN.Animation,&MAIN.Animation->CurrentAction,aa);
|
|
|
lstAppendItem(&MAIN.Animation->Actions,aa); laNotifyUsers("la.animation.actions");
|
|
|
return aa;
|
|
|
}
|
|
|
-laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p){
|
|
|
- laActionChannel* acf=0;
|
|
|
+laActionProp* laAnimationEnsureProp(void* hyper1, laProp* p){
|
|
|
int DataSize=la_GetKeyablePropertyStorageSize(p); if(!DataSize) return 0;
|
|
|
- for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
- if(ac->For==hyper1 && ac->Prop==p){ acf=ac; break; }
|
|
|
+ for(laActionProp* ap=MAIN.Animation->Props.pFirst;ap;ap=ap->Item.pNext){
|
|
|
+ if(ap->For==hyper1 && ap->Prop==p){ return ap; }
|
|
|
}
|
|
|
- if(acf) return acf;
|
|
|
- acf=memAcquire(sizeof(laActionChannel));
|
|
|
- memAssignRef(acf,&acf->For,hyper1); acf->Prop=p;
|
|
|
- acf->DataSize = DataSize;
|
|
|
+ laActionProp* ap = memAcquire(sizeof(laActionProp)); lstAppendItem(&MAIN.Animation->Props,ap);
|
|
|
+ memAssignRef(ap,&ap->For,hyper1); ap->Prop=p;
|
|
|
+ ap->DataSize = DataSize;
|
|
|
char _name[128]={0}, *name=_name; laTryGetInstanceIdentifier(hyper1, p->Container,_name,&name);
|
|
|
- strSafeSet(&acf->CachedName,name); strSafePrint(&acf->CachedName," ⯈ %s",p->Identifier);
|
|
|
- lstAppendItem(&aa->Channels,acf); laNotifyUsers("la.animation.current_action.channels");
|
|
|
- return acf;
|
|
|
+ strSafeSet(&ap->CachedName,name); strSafePrint(&ap->CachedName," ⯈ %s",p->Identifier);
|
|
|
+ return ap;
|
|
|
+}
|
|
|
+laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p){
|
|
|
+ laActionProp* ap=laAnimationEnsureProp(hyper1,p); if(!ap) return 0; laActionChannel* ac;
|
|
|
+ for(ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ if(ac->AP==ap) return ac;
|
|
|
+ }
|
|
|
+ ac=memAcquire(sizeof(laActionChannel)); ac->AP=ap;
|
|
|
+ lstAppendItem(&aa->Channels,ac); laNotifyUsers("la.animation.current_action.channels");
|
|
|
+ return ac;
|
|
|
}
|
|
|
laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame){
|
|
|
laActionKey* akf=0,*beforeakf=0;
|
|
@@ -52,7 +59,7 @@ laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame){
|
|
|
if(ak->At==frame){ akf=ak; break; } if(ak->At>frame){ beforeakf=ak; break; }
|
|
|
}
|
|
|
if(!akf){
|
|
|
- akf=memAcquireSimple(sizeof(laActionKey)-sizeof(uint64_t)+ac->DataSize);
|
|
|
+ akf=memAcquireSimple(sizeof(laActionKey)-sizeof(uint64_t)+ac->AP->DataSize);
|
|
|
akf->At=frame;
|
|
|
if(beforeakf){ lstInsertItemBefore(&ac->Keys, akf, beforeakf); }
|
|
|
else{ lstAppendItem(&ac->Keys, akf); }
|
|
@@ -60,9 +67,9 @@ laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame){
|
|
|
return akf;
|
|
|
}
|
|
|
void laAnimationStoreKeyValue(laActionChannel* ac, laActionKey* ak){
|
|
|
- laPropPack PP={0}; laPropStep PS={0};
|
|
|
- PS.p=ac->Prop; PS.Type='.'; PS.UseInstance=ac->For; PP.LastPs=&PS; PP.EndInstance=ac->For;
|
|
|
- switch(ac->Prop->PropertyType){
|
|
|
+ laPropPack PP={0}; laPropStep PS={0}; laActionProp* ap=ac->AP; if(!ap) return;
|
|
|
+ PS.p=ap->Prop; PS.Type='.'; PS.UseInstance=ap->For; PP.LastPs=&PS; PP.EndInstance=ap->For;
|
|
|
+ switch(ap->Prop->PropertyType){
|
|
|
case LA_PROP_INT: case LA_PROP_INT | LA_PROP_ARRAY: laGetIntArray(&PP,(int*)&ak->Data); break;
|
|
|
case LA_PROP_FLOAT: case LA_PROP_FLOAT | LA_PROP_ARRAY: laGetFloatArray(&PP,(real*)&ak->Data); break;
|
|
|
case LA_PROP_ENUM: case LA_PROP_ENUM | LA_PROP_ARRAY: laGetEnumArray(&PP,(laEnumItem**)&ak->Data); break;
|
|
@@ -71,7 +78,7 @@ void laAnimationStoreKeyValue(laActionChannel* ac, laActionKey* ak){
|
|
|
}
|
|
|
laActionKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p){
|
|
|
if(!aa) return 0;
|
|
|
- laActionChannel* ac=laAnimationEnsureChannel(aa,hyper1,p); if(!ac || !ac->For) return;
|
|
|
+ laActionChannel* ac=laAnimationEnsureChannel(aa,hyper1,p); if(!ac || !ac->AP || !ac->AP->For) return;
|
|
|
int frame=LA_ACTION_FRAME(aa);
|
|
|
laActionKey* ak=laAnimationEnsureFrame(ac,frame);
|
|
|
laAnimationStoreKeyValue(ac,ak);
|
|
@@ -101,8 +108,18 @@ int OPINV_AnimationPlayAction(laOperator *a, laEvent *e){
|
|
|
laAnimationSetPlayStatus(PlayStatus);
|
|
|
return LA_FINISHED;
|
|
|
}
|
|
|
+
|
|
|
+void la_AnimationActionSetOwnFrame(laAction* aa, int frame){
|
|
|
+ if(!aa) return;
|
|
|
+ aa->Offset+=(aa->PlayHead-(real)frame/aa->FrameCount)*aa->Length-1e-4;
|
|
|
+ la_AnimationEvaluateActions(0);
|
|
|
+ laNotifyUsers("la.animation.current_action");
|
|
|
+}
|
|
|
+
|
|
|
int OPINV_AnimationResetTime(laOperator *a, laEvent *e){
|
|
|
- laAnimationSetPlayHead(0);
|
|
|
+ char* arg=strGetArgumentString(a->ExtraInstructionsP,"current");
|
|
|
+ if(strSame(arg,"true")){ la_AnimationActionSetOwnFrame(MAIN.Animation->CurrentAction,0); return LA_FINISHED; }
|
|
|
+ laAnimationSetPlayHead(0); la_AnimationEvaluateActions(1);
|
|
|
return LA_FINISHED;
|
|
|
}
|
|
|
|
|
@@ -110,17 +127,20 @@ int OPINV_AnimationResetTime(laOperator *a, laEvent *e){
|
|
|
laActionChannel* laAnimationGetFrame(laActionChannel* ac, int frame){
|
|
|
if(ac->Keys.pFirst==ac->Keys.pLast){ return ac->Keys.pFirst; }
|
|
|
for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
|
|
|
- if(ak->At<=frame){ return ak; }
|
|
|
+ if(ak->At<=frame && ((!ak->Item.pNext) ||ak->Item.pNext && ((laActionKey*)ak->Item.pNext)->At>frame)){ return ak; }
|
|
|
}
|
|
|
return ac->Keys.pFirst;
|
|
|
}
|
|
|
|
|
|
+void la_AnimationMarkPropReset(){
|
|
|
+ for(laActionProp* ap=MAIN.Animation->Props.pFirst;ap;ap=ap->Item.pNext){ ap->Reset=1; }
|
|
|
+}
|
|
|
void la_AnimationInterpolateKeys(laActionChannel* ac, laActionKey* ak1, laActionKey* ak2, real PlayHead_mul_Length, void** data){
|
|
|
int* id1,*id2,*iret=(*data); real* fd1,*fd2,*fret=(*data);
|
|
|
- if(!ak2){ *data=&ak1->Data; return; }
|
|
|
- int arrlen=ac->Prop->Len?ac->Prop->Len:1;
|
|
|
+ if(!ak2){ *data=&ak1->Data; return; } laActionProp* ap=ac->AP; if(!ap) return;
|
|
|
+ int arrlen=ap->Prop->Len?ap->Prop->Len:1;
|
|
|
real fac=tnsGetRatiod(ak1->At,ak2->At,PlayHead_mul_Length); TNS_CLAMP(fac,0,1);
|
|
|
- switch(ac->Prop->PropertyType){
|
|
|
+ switch(ap->Prop->PropertyType){
|
|
|
case LA_PROP_INT: case LA_PROP_INT|LA_PROP_ARRAY:
|
|
|
id1=&ak1->Data;id2=&ak2->Data; for(int i=0;i<arrlen;i++){ iret[i]=tnsLinearItp(id1[i],id2[i],fac); } break;
|
|
|
case LA_PROP_FLOAT: case LA_PROP_FLOAT|LA_PROP_ARRAY:
|
|
@@ -129,10 +149,11 @@ void la_AnimationInterpolateKeys(laActionChannel* ac, laActionKey* ak1, laAction
|
|
|
*data=ak1->Data; break;
|
|
|
}
|
|
|
}
|
|
|
-void la_AnimationSetChannelValue(laActionChannel* ac, void* data){
|
|
|
- laPropPack PP={0}; laPropStep PS={0};
|
|
|
- PS.p=ac->Prop; PS.Type='.'; PS.UseInstance=ac->For; PP.LastPs=&PS; PP.EndInstance=ac->For;
|
|
|
- switch(ac->Prop->PropertyType){
|
|
|
+void la_AnimationSetPropValue(laActionProp* ap){
|
|
|
+ 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;
|
|
|
+ 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;
|
|
|
case LA_PROP_FLOAT: laSetFloat(&PP,*((real*)data)); break;
|
|
@@ -142,6 +163,22 @@ void la_AnimationSetChannelValue(laActionChannel* ac, void* data){
|
|
|
default: break;
|
|
|
}
|
|
|
}
|
|
|
+void la_AnimationMixChannelValue(laActionChannel* ac, void* data, int MixMode, real Factor){
|
|
|
+ laActionProp* ap=ac->AP; if(!ap) return; int* ip=&ap->Data,*ipd=data; real* fp=&ap->Data,*fpd=data;
|
|
|
+ int arrlen=ap->Prop->Len?ap->Prop->Len:1;
|
|
|
+ switch(ap->Prop->PropertyType){
|
|
|
+ case LA_PROP_INT: case LA_PROP_INT|LA_PROP_ARRAY: for(int i=0;i<arrlen;i++){
|
|
|
+ ip[i]=ap->Reset?ipd[i]:(MixMode==LA_ANIMATION_MIX_REPLACE?ipd[i]:(ipd[i]+ip[i]));
|
|
|
+ } break;
|
|
|
+ case LA_PROP_FLOAT: case LA_PROP_FLOAT|LA_PROP_ARRAY: for(int i=0;i<arrlen;i++){
|
|
|
+ fp[i]=ap->Reset?fpd[i]:(MixMode==LA_ANIMATION_MIX_REPLACE?fpd[i]:(fpd[i]+fp[i]));
|
|
|
+ } break;
|
|
|
+ case LA_PROP_ENUM: ip[0]=ipd[0]; break;
|
|
|
+ //case LA_PROP_ENUM|LA_PROP_ARRAY: laSetEnumArrayAllArray(&PP,(real*)data); break; //doesnt work
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ ap->Reset=0;
|
|
|
+}
|
|
|
void la_AnimationEvaluateActionChannels(laAction* aa){
|
|
|
int64_t _data[16]; void* data=_data;
|
|
|
int frame=LA_ACTION_FRAME(aa); real totframe=aa->PlayHead*aa->FrameCount;
|
|
@@ -149,33 +186,43 @@ void la_AnimationEvaluateActionChannels(laAction* aa){
|
|
|
laActionKey* ak1=laAnimationGetFrame(ac,frame); if(!ak1) continue;
|
|
|
laActionKey* ak2=ak1->Item.pNext;
|
|
|
la_AnimationInterpolateKeys(ac,ak1,ak2,totframe,&data);
|
|
|
- la_AnimationSetChannelValue(ac, data);
|
|
|
+ la_AnimationMixChannelValue(ac, data, aa->MixMode, 0);
|
|
|
}
|
|
|
}
|
|
|
-void la_AnimationEvaluateActions(){
|
|
|
+void la_AnimationEvaluateActions(int ClampOffsets){
|
|
|
int any=0;
|
|
|
+ la_AnimationMarkPropReset();
|
|
|
for(laAction* aa=MAIN.Animation->Actions.pFirst;aa;aa=aa->Item.pNext){
|
|
|
- real UseTime=MAIN.Animation->PlayHead-aa->Offset;
|
|
|
+ real preoffset=0,postoffset=aa->Offset/aa->Length;
|
|
|
+ if(ClampOffsets || (MAIN.Animation->PlayStatus!=LA_ANIMATION_STATUS_PAUSED)){
|
|
|
+ while(aa->Offset>aa->Length){ aa->Offset-=aa->Length; }
|
|
|
+ while(aa->Offset<-1e-6){ aa->Offset+=aa->Length; }
|
|
|
+ preoffset=aa->Offset; postoffset=0;
|
|
|
+ }
|
|
|
+ real UseTime=MAIN.Animation->PlayHead-preoffset;
|
|
|
int repeats=UseTime/aa->Length;
|
|
|
real remaining=UseTime-repeats*aa->Length;
|
|
|
while(remaining<0){ remaining+=aa->Length; }
|
|
|
- if(aa->PlayMode==LA_ANIMATION_PLAY_MODE_REPEAT){ aa->PlayHead=remaining/aa->Length; }
|
|
|
- elif(aa->PlayMode==LA_ANIMATION_PLAY_MODE_HOLD){ aa->PlayHead=(UseTime>aa->Length)?1.0:(UseTime<0?0:UseTime/aa->Length); }
|
|
|
- elif(aa->PlayMode==LA_ANIMATION_PLAY_MODE_BOUNCE){ real t=remaining/aa->Length; aa->PlayHead=(repeats%2)?(1-t):t; }
|
|
|
+ if(aa->PlayMode==LA_ANIMATION_PLAY_MODE_REPEAT){ aa->PlayHead=remaining/aa->Length-postoffset; }
|
|
|
+ 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);
|
|
|
}
|
|
|
+ for(laActionProp* ap=MAIN.Animation->Props.pFirst;ap;ap=ap->Item.pNext){ if(ap->Reset){ continue; }
|
|
|
+ la_AnimationSetPropValue(ap);
|
|
|
+ }
|
|
|
if(any) laNotifyUsers("la.animation");
|
|
|
}
|
|
|
|
|
|
void la_AnimationPreFrame(){
|
|
|
if(MAIN.Animation->PlayHead<0){
|
|
|
MAIN.Animation->PlayHead=0; laAnimationSetPlayStatus(0);
|
|
|
- la_AnimationEvaluateActions();
|
|
|
+ la_AnimationEvaluateActions(1);
|
|
|
laNotifyUsers("la.animation.play_head");
|
|
|
}
|
|
|
if(MAIN.Animation->PlayStatus){
|
|
|
- la_AnimationEvaluateActions();
|
|
|
+ la_AnimationEvaluateActions(0);
|
|
|
}
|
|
|
}
|
|
|
void la_AnimationPostFrame(){
|
|
@@ -188,8 +235,73 @@ void la_AnimationPostFrame(){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void laget_AnimationChannelName(laActionChannel *p, char *result, char** here){
|
|
|
-
|
|
|
+void la_ActionDeselectFrames(laAction* aa){
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
|
|
|
+ ak->Selected=0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+void la_ActionSelectFrame(laAction* aa, int Channel, real At, real zoomx){
|
|
|
+ int tc=0;laActionChannel* ac;
|
|
|
+ for(ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){ if(tc==Channel) break; tc++; }
|
|
|
+ if(!ac) return;
|
|
|
+ real ClosestDist=FLT_MAX; laActionKey* ClosestKey=0;
|
|
|
+ for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
|
|
|
+ real d=fabs(ak->At-At+0.5); if(d*zoomx<LA_RH*2 && d<ClosestDist){ ClosestDist=d; ClosestKey=ak; }
|
|
|
+ }
|
|
|
+ if(ClosestKey){ ClosestKey->Selected=1; }
|
|
|
+}
|
|
|
+int la_ActionSaveKeyOriginalAt(laAction* aa){
|
|
|
+ int any=0;
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){ if(!ak->Selected) continue; any=1; ak->OriginaAt=ak->At; }
|
|
|
+ }
|
|
|
+ return any;
|
|
|
+}
|
|
|
+void la_ActionRestoreKeyOriginalAt(laAction* aa){
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){ if(!ak->Selected) continue; ak->At=ak->OriginaAt; }
|
|
|
+ }
|
|
|
+ la_ActionEnsureFrameOrder(aa);
|
|
|
+}
|
|
|
+void la_ActionEnsureFrameOrder(laAction* aa){
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ laListHandle lst={0};
|
|
|
+ laActionKey* ak; while(ak=lstPopItem(&ac->Keys)){ int done=0;
|
|
|
+ if(!lst.pFirst){ lstAppendItem(&lst,ak); continue; }
|
|
|
+ laActionKey* ak2=0;
|
|
|
+ for(ak2=lst.pFirst;ak2;ak2=ak2->Item.pNext){
|
|
|
+ if(ak2->At>=ak->At){ lstInsertItemBefore(&lst,ak,ak2); done=1; break; }
|
|
|
+ }
|
|
|
+ if(!done) lstAppendItem(&lst,ak);
|
|
|
+ }
|
|
|
+ lstCopyHandle(&ac->Keys,&lst);
|
|
|
+ }
|
|
|
+}
|
|
|
+void la_ActionRemoveDuplicatedFrames(laAction* aa){
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ laActionKey* ak2; for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
|
|
|
+ while((ak2=ak->Item.pNext)&&ak->At==ak2->At){ lstRemoveItem(&ac->Keys,ak2); memLeave(ak2); }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+void la_ActionMoveSelectedFrames(laAction* aa, int Delta){
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){ if(!ak->Selected) continue;
|
|
|
+ ak->At=ak->OriginaAt+Delta;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ la_ActionEnsureFrameOrder(aa);
|
|
|
+}
|
|
|
+int la_ActionDeleteSelectedFrames(laAction* aa){
|
|
|
+ int any=0;
|
|
|
+ for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ laActionKey* NextAk; for(laActionKey* ak=ac->Keys.pFirst;ak;ak=NextAk){ NextAk=ak->Item.pNext;if(!ak->Selected) continue;
|
|
|
+ lstRemoveItem(&ac->Keys, ak); memLeave(ak); any=1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return any;
|
|
|
}
|
|
|
|
|
|
int LAMOD_AnimationActionsCanvas(laOperator *a, laEvent *e){
|
|
@@ -213,13 +325,27 @@ int LAMOD_AnimationActionsCanvas(laOperator *a, laEvent *e){
|
|
|
ex->PanY-=e->y-ex->ClickedY; ex->PanX-=e->x-ex->ClickedX;
|
|
|
ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1;
|
|
|
}
|
|
|
- }elif(ex->UiMode==2){
|
|
|
+ }elif(ex->UiMode==2){ Modal=1;
|
|
|
if(e->Type&LA_MOUSE_EVENT){
|
|
|
- ex->LW=e->x-ui->L+LA_SEAM_W; ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1;
|
|
|
+ ex->LW=e->x-ui->L+LA_SEAM_W; ex->ClickedX=e->x; ex->ClickedY=e->y;
|
|
|
if(ex->LW<LA_RH*3 && ex->LW>=LA_RH/2){ ex->LW=LA_RH*3; }
|
|
|
if(ex->LW<LA_RH/2 && ex->Dragging!=12){ ex->ShowLegend=0; ex->LW=0; }
|
|
|
if(ex->LW<LA_RH*3){ ex->LW=LA_RH*3;}
|
|
|
}
|
|
|
+ }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);
|
|
|
+ }
|
|
|
+ }elif(ex->UiMode==4){ Modal=1;
|
|
|
+ if(e->Type==LA_R_MOUSE_DOWN || (e->Type==LA_ESCAPE_DOWN)){ ex->UiMode=0; ex->Dragging=0;
|
|
|
+ la_ActionRestoreKeyOriginalAt(aa); laNotifyUsers("la.animation.current_action");
|
|
|
+ }elif(e->Type==LA_L_MOUSE_DOWN){ la_ActionRemoveDuplicatedFrames(aa);
|
|
|
+ laNotifyUsers("la.animation.current_action"); ex->UiMode=0; ex->Dragging=0;
|
|
|
+ }elif(e->Type&LA_MOUSE_EVENT){ Modal=1;
|
|
|
+ int ToFrame=(real)(e->x-tl+ex->PanX)/ex->ZoomX/FW,FromFrame=(real)(ex->ClickedX-tl+ex->PanX)/ex->ZoomX/FW;
|
|
|
+ la_ActionMoveSelectedFrames(aa,ToFrame-FromFrame); laNotifyUsers("la.animation.current_action");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int MaxDN=LA_RH*(Channels+1)-H+bt->TP+bt->BP; if(MaxDN<0) MaxDN=0;
|
|
@@ -232,17 +358,36 @@ int LAMOD_AnimationActionsCanvas(laOperator *a, laEvent *e){
|
|
|
ex->UiMode=2; ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1; ex->Dragging=10; Modal=1;
|
|
|
}
|
|
|
}else{ if(ex->TargetIndexVali){ ex->TargetIndexVali=0; Modal=1; } }
|
|
|
- }else{
|
|
|
+ }elif(aa){
|
|
|
if((!ex->ShowLegend)&&e->x<=ll+LA_SEAM_W*2){
|
|
|
if(!ex->TargetIndexVali){ ex->TargetIndexVali=1; Modal=1; }
|
|
|
if(e->Type==LA_L_MOUSE_DOWN){ ex->LW=LA_RH*4; ex->Dragging=12; ex->ShowLegend=1; Modal=1; ex->UiMode=2; ex->TargetIndexVali=1; }
|
|
|
}else{ if(ex->TargetIndexVali){ ex->TargetIndexVali=0; Modal=1; } }
|
|
|
if(e->Type==LA_MOUSE_WHEEL_DOWN){ ex->ZoomX*=0.9; ex->PanX+=mid; ex->PanX*=0.9; ex->PanX-=mid; Modal=1; }
|
|
|
- if(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_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;
|
|
|
+ }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); }
|
|
|
+ la_ActionSelectFrame(aa,row,at,ex->ZoomX);
|
|
|
+ laNotifyUsers("la.animation.current_action");
|
|
|
+ }elif(e->Type==LA_KEY_DOWN&&e->key=='g'){
|
|
|
+ int any=la_ActionSaveKeyOriginalAt(aa);
|
|
|
+ if(any){ ex->ClickedX=e->x; ex->ClickedY=e->y; ex->UiMode=4; Modal=1; ex->Dragging=13;
|
|
|
+ laNotifyUsers("la.animation.current_action");
|
|
|
+ }
|
|
|
+ }elif(e->Type==LA_KEY_DOWN&&e->key=='x'){
|
|
|
+ int any=la_ActionDeleteSelectedFrames(aa);
|
|
|
+ if(any){
|
|
|
+ laNotifyUsers("la.animation.current_action");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
if(ex->PanY>MaxDN){ ex->PanY=MaxDN; } if(ex->PanY<0){ ex->PanY=0; }
|
|
|
- if(ex->PanX<0){ ex->PanX=0; }
|
|
|
+ //if(ex->PanX<0){ ex->PanX=0; }
|
|
|
|
|
|
if(ex->TargetIndexVali){ laSetWindowCursor(LA_LEFT_AND_RIGHT); }else{ laSetWindowCursor(LA_ARROW); }
|
|
|
|
|
@@ -302,7 +447,8 @@ void la_AnimationActionDrawCanvas(laBoxedTheme *bt, laAction *aa, laUiItem* ui){
|
|
|
real ku=ui->U+bt->TP+row*LA_RH-ex->PanY,kb=ku+LA_RH;
|
|
|
for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
|
|
|
real kl=tl+ak->At*FW*ex->ZoomX-ex->PanX, kr=tl+(ak->At+1)*FW*ex->ZoomX-ex->PanX;
|
|
|
- if(curframe==ak->At) tnsColor4d(LA_COLOR3(txt),txt[3]*0.6);
|
|
|
+ if(ak->Selected) tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE));
|
|
|
+ elif(curframe==ak->At) tnsColor4d(LA_COLOR3(txt),txt[3]*0.6);
|
|
|
else tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE));
|
|
|
tnsVertex2d(kl, ku); tnsVertex2d(kr, ku);
|
|
|
tnsVertex2d(kr, kb); tnsVertex2d(kl, kb);
|
|
@@ -316,14 +462,25 @@ void la_AnimationActionDrawCanvas(laBoxedTheme *bt, laAction *aa, laUiItem* ui){
|
|
|
}
|
|
|
tnsFlush(); glLineWidth(1);
|
|
|
|
|
|
+ real end=tl+aa->FrameCount*FW*ex->ZoomX-ex->PanX;
|
|
|
+ tnsColor4d(0,0,0,0.3);
|
|
|
+ tnsVertex2d(end, ui->U+LA_RH); tnsVertex2d(end+1e6, ui->U+LA_RH);
|
|
|
+ tnsVertex2d(end+1e6, ui->B); tnsVertex2d(end, ui->B);
|
|
|
+ tnsPackAs(GL_TRIANGLE_FAN);
|
|
|
+ tnsVertex2d(tl-ex->PanX, ui->U+LA_RH); tnsVertex2d(tl-ex->PanX-1e6, ui->U+LA_RH);
|
|
|
+ tnsVertex2d(tl-ex->PanX-1e6, ui->B); tnsVertex2d(tl-ex->PanX, ui->B);
|
|
|
+ tnsPackAs(GL_TRIANGLE_FAN);
|
|
|
+
|
|
|
tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE));
|
|
|
- cx=tl+aa->PlayHead*aa->FrameCount*FW*ex->ZoomX-ex->PanX; tnsVertex2d(cx, ui->U); tnsVertex2d(cx, ui->B);
|
|
|
+ int FrameFix=aa->PlayHead<0?1:0;
|
|
|
+ cx=tl+(aa->PlayHead*aa->FrameCount+FrameFix)*FW*ex->ZoomX-ex->PanX; tnsVertex2d(cx, ui->U); tnsVertex2d(cx, ui->B);
|
|
|
tnsPackAs(GL_LINES); glLineWidth(3); tnsFlush(); glLineWidth(1);
|
|
|
+
|
|
|
+ char buf[32]; sprintf(buf,"%d",curframe); real tlen=tnsStringGetDimension(buf,0,0,0,0,0)+bt->LP+bt->RP;
|
|
|
tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE));
|
|
|
- tnsVertex2d(cx, ui->U+LA_RH); tnsVertex2d(cx+LA_RH, ui->U+LA_RH);
|
|
|
- tnsVertex2d(cx+LA_RH, ui->U); tnsVertex2d(cx, ui->U);
|
|
|
+ tnsVertex2d(cx, ui->U+LA_RH); tnsVertex2d(cx+tlen, ui->U+LA_RH);
|
|
|
+ tnsVertex2d(cx+tlen, ui->U); tnsVertex2d(cx, ui->U);
|
|
|
tnsPackAs(GL_TRIANGLE_FAN);
|
|
|
- char buf[32]; sprintf(buf,"%d",curframe);
|
|
|
tnsDrawStringAuto(buf,laThemeColor(bt,LA_BT_TEXT_ACTIVE),cx+bt->LP,cx+LA_RH*2,ui->U+bt->TP,0);
|
|
|
tnsPackAs(GL_TRIANGLE_FAN); tnsUseNoTexture();
|
|
|
}
|
|
@@ -336,8 +493,9 @@ void la_AnimationActionDrawCanvas(laBoxedTheme *bt, laAction *aa, laUiItem* ui){
|
|
|
if(!aa){
|
|
|
tnsDrawStringAuto("No action selected",laThemeColor(bt,LA_BT_TEXT),ll+bt->LP,lr-bt->RP,ui->U+bt->BP,0);
|
|
|
}else{ int row=1;
|
|
|
+ tnsDrawStringAuto(aa->Name->Ptr,laThemeColor(bt,LA_BT_TEXT),ll+bt->LP,lr-bt->RP,ui->U+bt->BP,0);
|
|
|
for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
- tnsDrawStringAuto(ac->CachedName->Ptr,laThemeColor(bt,LA_BT_TEXT),ll+bt->LP,lr-bt->RP,ui->U+bt->TP+row*LA_RH-ex->PanY,0);
|
|
|
+ tnsDrawStringAuto(ac->AP->CachedName->Ptr,laThemeColor(bt,LA_BT_TEXT),ll+bt->LP,lr-bt->RP,ui->U+bt->TP+row*LA_RH-ex->PanY,0);
|
|
|
row++;
|
|
|
}
|
|
|
}
|