*/}}
Parcourir la source

Key interpolation basics

YimingWu il y a 1 an
Parent
commit
dedec6e6fb
5 fichiers modifiés avec 174 ajouts et 204 suppressions
  1. 65 17
      la_animation.c
  2. 2 0
      la_data.c
  3. 15 6
      la_data.h
  4. 57 153
      resources/la_operators.c
  5. 35 28
      resources/la_properties.c

+ 65 - 17
la_animation.c

@@ -31,50 +31,51 @@ laAction* laAnimiationNewAction(char* Name){
     lstAppendItem(&MAIN.Animation->Actions,aa); laNotifyUsers("la.animation.actions");
     return aa;
 }
-laAnimationChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p){
-    laAnimationChannel* acf=0;
+laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p){
+    laActionChannel* acf=0;
     int DataSize=la_GetKeyablePropertyStorageSize(p); if(!DataSize) return 0;
-    for(laAnimationChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
+    for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
         if(ac->For==hyper1 && ac->Prop==p){ acf=ac; break; }
     }
     if(acf) return acf;
-    acf=memAcquire(sizeof(laAnimationChannel));
+    acf=memAcquire(sizeof(laActionChannel));
     memAssignRef(acf,&acf->For,hyper1); acf->Prop=p;
     acf->DataSize = DataSize;
     lstAppendItem(&aa->Channels,acf);
     return acf;
 }
-laAnimationChannel* laAnimationEnsureFrame(laAnimationChannel* ac, int frame){
-    laAnimationKey* akf=0,*beforeakf=0;
-    for(laAnimationKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
+laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame){
+    laActionKey* akf=0,*beforeakf=0;
+    for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
         if(ak->At==frame){ akf=ak; break; } if(ak->At>frame){ beforeakf=ak; break; }
     }
     if(!akf){
-        akf=memAcquireSimple(sizeof(laAnimationKey)-sizeof(uint64_t)+ac->DataSize);
+        akf=memAcquireSimple(sizeof(laActionKey)-sizeof(uint64_t)+ac->DataSize);
         akf->At=frame;
         if(beforeakf){ lstInsertItemBefore(&ac->Keys, akf, beforeakf); }
         lstAppendItem(&ac->Keys, akf);
     }
     return akf;
 }
-void laAnimationStoreKeyValue(laAnimationChannel* ac, laAnimationKey* ak){
+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){
-    case LA_PROP_INT: case LA_PROP_INT | LA_PROP_ARRAY:     laGetIntArray(&PP,(int*)&ak->Data);
-    case LA_PROP_FLOAT: case LA_PROP_FLOAT | LA_PROP_ARRAY: laGetFloatArray(&PP,(real*)&ak->Data);
-    case LA_PROP_ENUM: case LA_PROP_ENUM | LA_PROP_ARRAY:   laGetEnumArray(&PP,(laEnumItem**)&ak->Data);
+    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;
     case LA_PROP_SUB: case LA_PROP_OPERATOR: case LA_PROP_STRING: case LA_PROP_RAW: default: return;
     }
 }
-laAnimationKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p){
-    laAnimationChannel* ac=laAnimationEnsureChannel(aa,hyper1,p); if(!ac || !ac->For) return;
-    int frame=(aa->PlayHead*(real)aa->FrameCount+0.5);
-    laAnimationKey* ak=laAnimationEnsureFrame(ac->DataSize,frame);
+laActionKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p){
+    if(!aa) return 0;
+    laActionChannel* ac=laAnimationEnsureChannel(aa,hyper1,p); if(!ac || !ac->For) return;
+    int frame=LA_ACTION_FRAME(aa);
+    laActionKey* ak=laAnimationEnsureFrame(ac,frame);
     laAnimationStoreKeyValue(ac,ak);
+    return ak;
 }
 
-
 void laAnimationSetPlayStatus(int PlayStatus){
     if(PlayStatus>3||PlayStatus<0) PlayStatus=0; MAIN.Animation->PlayStatus=PlayStatus;
     if(PlayStatus) laRecordTime(&MAIN.Animation->TimeOrigin);
@@ -102,6 +103,52 @@ int OPINV_AnimationResetTime(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 
+
+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; }
+    }
+    return ac->Keys.pFirst;
+}
+
+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;
+    real fac=tnsGetRatiod(ak1->At,ak2->At,PlayHead_mul_Length); TNS_CLAMP(fac,0,1);
+    switch(ac->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:
+        fd1=&ak1->Data;fd2=&ak2->Data; for(int i=0;i<arrlen;i++){ fret[i]=tnsLinearItp(fd1[i],fd2[i],fac); } break;
+    default:
+        *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){
+    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;
+    case LA_PROP_FLOAT|LA_PROP_ARRAY: laSetFloatArrayAllArray(&PP,(real*)data); break;
+    case LA_PROP_ENUM: laSetEnum(&PP,*((int*)data)); break;
+    //case LA_PROP_ENUM|LA_PROP_ARRAY: laSetEnumArrayAllArray(&PP,(real*)data); break; //doesnt work
+    default: break;
+    }
+}
+void la_AnimationEvaluateActionChannels(laAction* aa){
+    int64_t _data[16]; void* data=_data;
+    int frame=LA_ACTION_FRAME(aa); real totframe=aa->PlayHead*aa->FrameCount;
+    for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
+        laActionKey* ak1=laAnimationGetFrame(ac,frame); if(!ak1) continue;
+        laActionKey* ak2=ak1->Item.pNext;
+        la_AnimationInterpolateKeys(ac,ak1,ak2,totframe,&data);
+        la_AnimationSetChannelValue(ac, data);
+    }
+}
 void la_AnimationEvaluateActions(){
     int any=0;
     for(laAction* aa=MAIN.Animation->Actions.pFirst;aa;aa=aa->Item.pNext){
@@ -113,6 +160,7 @@ void la_AnimationEvaluateActions(){
         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; }
         any=1;
+        la_AnimationEvaluateActionChannels(aa);
     }
     if(any) laNotifyUsers("la.animation");
 }

+ 2 - 0
la_data.c

@@ -817,6 +817,8 @@ laProp *la_CreateProperty(laPropContainer *Container, int Type, const char *Iden
     p->UDFReadProgress = (Tag & LA_PROP_READ_PROGRESS)?1:0;
     p->CanTranslate = (Tag & LA_TRANSLATE)?1:0;
     if(p->IsRadAngle&&(!p->Unit)) p->Unit="°"; 
+    p->Keyable = (Tag & LA_PROP_KEYABLE)? 1 : 0;
+    if(Tag&LA_PROP_ROTATION){ p->KeySpecialInterpolation=LA_PROP_KEY_INTERPOLATION_ROTATION; }
 
     return p;
 }

+ 15 - 6
la_data.h

@@ -117,6 +117,8 @@ typedef void (*laContainerpUDFPropagateF)(void *, void* udf, int Force);
 
 #define LA_RAW_CSTR_MAX_LEN 4096
 
+#define LA_PROP_KEY_INTERPOLATION_ROTATION 1
+
 typedef void (*laUiDefineFunc)(void *uil, void *collection_inst, void *this_inst, void *extra_col, int temlpate_context);
 typedef void (*laPanelDetachedPropFunc)(void *panel);
 
@@ -226,6 +228,8 @@ STRUCTURE(laProp){
     char UDFReadProgress;
     char IsRadAngle;
     char CanTranslate;
+    char Keyable;
+    char KeySpecialInterpolation;
 
     //int           SignalThrow;
     //int           SignalCatch;
@@ -672,19 +676,22 @@ STRUCTURE(laAction){
     int PlayMode;
     int Solo, Mute;
 };
-STRUCTURE(laAnimationChannel){
+STRUCTURE(laActionChannel){
     laListItem Item;
     void* For;
     laProp* Prop;
     int DataSize; // sizeof
     laListHandle Keys;
 };
-STRUCTURE(laAnimationKey){
+STRUCTURE(laActionKey){
     laListItem Item;
     int At;
     uint64_t Data; // variable size depending on property;
 };
 
+#define LA_ACTION_FRAME(aa)\
+    (aa->PlayHead*(real)aa->FrameCount+0.5)
+
     //STRUCTURE(laUDFFailNode) {
     //	laListItemPointer Item;
     //	laPropContainer*  pc;
@@ -735,6 +742,8 @@ STRUCTURE(laAnimationKey){
 #define LA_READ_ONLY (1<<27)
 #define LA_HIDE_IN_SAVE (1<<28)
 #define LA_TRANSLATE (1<<29)
+#define LA_PROP_KEYABLE   (1<<30)
+#define LA_PROP_ROTATION  (1<<31)
 
 STRUCTURE(laThreadNotifier){
     laListItem Item;
@@ -1010,10 +1019,10 @@ void laRedo();
 #define LA_ANIMATION_STATUS_PLAY_REV 2
 
 laAction* laAnimiationNewAction(char* Name);
-laAnimationChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p);
-laAnimationChannel* laAnimationEnsureFrame(laAnimationChannel* ac, int frame);
-void laAnimationStoreKeyValue(laAnimationChannel* ac, laAnimationKey* ak);
-laAnimationKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p);
+laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p);
+laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame);
+void laAnimationStoreKeyValue(laActionChannel* ac, laActionKey* ak);
+laActionKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p);
 
 void laAnimationSetPlayStatus(int PlayStatus);
 void laAnimationSetPlayHead(real time);

+ 57 - 153
resources/la_operators.c

@@ -734,150 +734,54 @@ int OPINV_TerminateProgram(laOperator *a, laEvent *e){
     return LA_OPERATOR_CALLS_SHUTOFF;
 }
 
-int OPCHK_IntSetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_INT)) return 1;
-    else
-        return 0;
-}
-int OPCHK_FloatSetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_FLOAT)) return 1;
-    else
-        return 0;
-}
-int OPCHK_IntArraySetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_INT | LA_PROP_ARRAY)) return 1;
-    else
-        return 0;
-}
-int OPCHK_FloatArraySetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_FLOAT | LA_PROP_ARRAY)) return 1;
-    else
-        return 0;
-}
-int OPCHK_EnumSetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_ENUM)) return 1;
-    else
-        return 0;
-}
-int OPCHK_EnumArraySetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_ENUM | LA_PROP_ARRAY)) return 1;
-    else
-        return 0;
+int OPCHK_PropSetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (!This->LastPs->p->ReadOnly)) return 1;
+    else return 0;
 }
 int OPCHK_StringSetValue(laPropPack *This, laStringSplitor *Instructions){
-    if (This && (This->LastPs->p->PropertyType == LA_PROP_STRING)) return 1;
-    else
-        return 0;
-}
-int OPINV_EnumSetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_ENUM)){
-        laEnumProp *ep = a->This->LastPs->p;
-        laSetEnum(a->This, ep->DefVal);
-    }
-    return LA_FINISHED;
-}
-int OPINV_IntSetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
-        laIntProp *ip = a->This->LastPs->p;
-        laSetInt(a->This, ip->DefVal);
-    }
-    return LA_FINISHED;
-}
-int OPINV_FloatSetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
-        laFloatProp *ip = a->This->LastPs->p;
-        laSetFloat(a->This, ip->DefVal);
-    }
-    return LA_FINISHED;
-}
-int OPINV_IntSetMax(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
-        laIntProp *ip = a->This->LastPs->p;
-        laSetInt(a->This, ip->Max);
-    }
-    return LA_FINISHED;
-}
-int OPINV_FloatSetMax(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
-        laFloatProp *ip = a->This->LastPs->p;
-        laSetFloat(a->This, ip->Max);
-    }
-    return LA_FINISHED;
-}
-int OPINV_IntSetMin(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
-        laIntProp *ip = a->This->LastPs->p;
-        laSetInt(a->This, ip->Min);
-    }
-    return LA_FINISHED;
-}
-int OPINV_FloatSetMin(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
-        laFloatProp *ip = a->This->LastPs->p;
-        laSetFloat(a->This, ip->Min);
-    }
-    return LA_FINISHED;
-}
-int OPINV_EnumArraySetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_ENUM)){
-        laEnumProp *ep = a->This->LastPs->p;
-        laSetEnumArrayAll(a->This, ep->DefVal);
-    }
-    return LA_FINISHED;
-}
-int OPINV_IntArraySetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
-        laIntProp *ip = a->This->LastPs->p;
-        if (ip->DefArr) laSetIntArrayAllArray(a->This, ip->DefArr);
-        else
-            laSetIntArrayAll(a->This, ip->DefVal);
-    }
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_STRING) && (!This->LastPs->p->ReadOnly)) return 1;
+    else return 0;
+}
+int OPINV_PropSetDefault(laOperator *a, laEvent *e){
+    if(!a->This) return LA_CANCELED; laProp* p=a->This->LastPs->p;
+    if (p->PropertyType==LA_PROP_ENUM){
+        laEnumProp *ep = a->This->LastPs->p; laSetEnum(a->This, ep->DefVal); }
+    elif (p->PropertyType==(LA_PROP_ENUM|LA_PROP_ARRAY)){
+        laEnumProp *ep = a->This->LastPs->p; laSetEnumArrayAll(a->This, ep->DefVal); }
+    elif (p->PropertyType==LA_PROP_INT){
+        laIntProp *ip = a->This->LastPs->p; laSetInt(a->This, ip->DefVal);}
+    elif (p->PropertyType==(LA_PROP_INT|LA_PROP_ARRAY)){ laIntProp *ip = a->This->LastPs->p;
+        if (ip->DefArr) laSetIntArrayAllArray(a->This, ip->DefArr); else laSetIntArrayAll(a->This, ip->DefVal); }
+    elif (p->PropertyType==LA_PROP_FLOAT){
+        laFloatProp *ip = a->This->LastPs->p; laSetFloat(a->This, ip->DefVal); }
+    elif (p->PropertyType==(LA_PROP_FLOAT|LA_PROP_ARRAY)){ laFloatProp *ip = a->This->LastPs->p;
+        if (ip->DefArr) laSetFloatArrayAllArray(a->This, ip->DefArr); else laSetFloatArrayAll(a->This, ip->DefVal); }
+    elif (p->PropertyType==LA_PROP_STRING){laStringProp *sp = a->This->LastPs->p;
+        if (sp->DefStr) laSetString(a->This, sp->DefStr); else laSetString(a->This, ""); }
     return LA_FINISHED;
 }
-int OPINV_FloatArraySetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
-        laFloatProp *ip = a->This->LastPs->p;
-        if (ip->DefArr) laSetFloatArrayAllArray(a->This, ip->DefArr);
-        else
-            laSetFloatArrayAll(a->This, ip->DefVal);
-    }
+int OPINV_PropSetMax(laOperator *a, laEvent *e){
+    if(!a->This) return LA_CANCELED; laProp* p=a->This->LastPs->p;
+    if (p->PropertyType==LA_PROP_INT){
+        laIntProp *ip = a->This->LastPs->p; laSetInt(a->This, ip->Max); }
+    elif (p->PropertyType==(LA_PROP_INT|LA_PROP_ARRAY)){ 
+        laIntProp *ip = a->This->LastPs->p; laSetIntArrayAll(a->This, ip->Max); }
+    elif (p->PropertyType==LA_PROP_FLOAT){
+        laFloatProp *ip = a->This->LastPs->p; laSetFloat(a->This, ip->Max); }
+    elif (p->PropertyType==(LA_PROP_FLOAT|LA_PROP_ARRAY)){
+        laFloatProp *ip = a->This->LastPs->p; laSetFloatArrayAll(a->This, ip->Max); }
     return LA_FINISHED;
 }
-int OPINV_IntArraySetMax(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
-        laIntProp *ip = a->This->LastPs->p;
-        laSetIntArrayAll(a->This, ip->Max);
-    }
-    return LA_FINISHED;
-}
-int OPINV_FloatArraySetMax(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
-        laFloatProp *ip = a->This->LastPs->p;
-        laSetFloatArrayAll(a->This, ip->Max);
-    }
-    return LA_FINISHED;
-}
-int OPINV_IntArraySetMin(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
-        laIntProp *ip = a->This->LastPs->p;
-        laSetIntArrayAll(a->This, ip->Min);
-    }
-    return LA_FINISHED;
-}
-int OPINV_FloatArraySetMin(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
-        laFloatProp *ip = a->This->LastPs->p;
-        laSetFloatArrayAll(a->This, ip->Min);
-    }
-    return LA_FINISHED;
-}
-int OPINV_StringSetDefault(laOperator *a, laEvent *e){
-    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_STRING)){
-        laStringProp *sp = a->This->LastPs->p;
-        if (sp->DefStr) laSetString(a->This, sp->DefStr);
-        else
-            laSetString(a->This, "");
-    }
+int OPINV_PropSetMin(laOperator *a, laEvent *e){
+    if(!a->This) return LA_CANCELED; laProp* p=a->This->LastPs->p;
+    if (p->PropertyType==LA_PROP_INT){
+        laIntProp *ip = a->This->LastPs->p; laSetInt(a->This, ip->Min); }
+    elif (p->PropertyType==(LA_PROP_INT|LA_PROP_ARRAY)){ 
+        laIntProp *ip = a->This->LastPs->p; laSetIntArrayAll(a->This, ip->Min); }
+    elif (p->PropertyType==LA_PROP_FLOAT){
+        laFloatProp *ip = a->This->LastPs->p; laSetFloat(a->This, ip->Min); }
+    elif (p->PropertyType==(LA_PROP_FLOAT|LA_PROP_ARRAY)){
+        laFloatProp *ip = a->This->LastPs->p; laSetFloatArrayAll(a->This, ip->Min); }
     return LA_FINISHED;
 }
 
@@ -1002,6 +906,15 @@ int OPINV_CombineChildBlocks(laOperator *a, laEvent *e){
     return LA_CANCELED;
 }
 
+int OPCHK_PropInsertKey(laPropPack *This, laStringSplitor *Instructions){
+    if (MAIN.Animation->CurrentAction && This && This->LastPs->p->Keyable) return 1;
+    else return 0;
+}
+int OPINV_PropInsertKey(laOperator *a, laEvent *e){
+    laAnimationInsertKeyFrame(MAIN.Animation->CurrentAction,a->This->LastPs->UseInstance,a->This->LastPs->p);
+    return LA_FINISHED;
+}
+
 STRUCTURE(laNewPanelData){
     laUiTemplate* SelectedTemplate;
     laBlock* b;
@@ -2154,23 +2067,14 @@ void la_RegisterBuiltinOperators(){
     laCreateOperatorType("LA_dock_panel", "Dock Panel", "Dock a panel",
                           OPCHK_IsPanel, 0, 0, OPINV_DockPanel, 0, 0, LA_ACTUATOR_SYSTEM);
     
-    laCreateOperatorType("LA_int_restore_default", "Restore Default Value", "Restore Int Value To Default", OPCHK_IntSetValue, 0, 0, OPINV_IntSetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_real_restore_default", "Restore Default Value", "Restore Float Value To Default", OPCHK_FloatSetValue, 0, 0, OPINV_FloatSetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_int_set_max", "Set Max Value", "Set Int Value To Max", OPCHK_IntSetValue, 0, 0, OPINV_IntSetMax, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_real_set_max", "Set Max Value", "Set Float Value To Max", OPCHK_FloatSetValue, 0, 0, OPINV_FloatSetMax, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_int_set_min", "Set Min Value", "Set Int Value To Min", OPCHK_IntSetValue, 0, 0, OPINV_IntSetMin, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_real_set_min", "Set Min Value", "Set Float Value To Min", OPCHK_FloatSetValue, 0, 0, OPINV_FloatSetMin, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_int_array_restore_default", "Restore Default Array/Value", "Restore Int Values To Default", OPCHK_IntArraySetValue, 0, 0, OPINV_IntArraySetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_real_array_restore_default", "Restore Default Array/Value", "Restore Float Values To Default", OPCHK_FloatArraySetValue, 0, 0, OPINV_FloatArraySetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_int_array_set_max", "Set Max Values", "Set Int Values To Max", OPCHK_IntArraySetValue, 0, 0, OPINV_IntArraySetMax, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_real_array_set_max", "Set Max Values", "Set Float Values To Max", OPCHK_FloatArraySetValue, 0, 0, OPINV_FloatArraySetMax, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_int_array_set_min", "Set Min Values", "Set Int Values To Min", OPCHK_IntArraySetValue, 0, 0, OPINV_IntArraySetMin, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_real_array_set_min", "Set Min Values", "Set Float Values To Min", OPCHK_FloatArraySetValue, 0, 0, OPINV_FloatArraySetMin, 0, 0, LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_enum_restore_default", "Restore Default Value", "Restore enum value to default", OPCHK_EnumSetValue, 0, 0, OPINV_EnumSetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_enum_array_restore_default", "Restore Default Array", "Restore enum array values to default", OPCHK_EnumArraySetValue, 0, 0, OPINV_EnumArraySetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
-    laCreateOperatorType("LA_string_set_default", "Set Default Value", "Set default string", OPCHK_StringSetValue, 0, 0, OPINV_StringSetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_prop_restore_default", "Restore Default Value", "Restore property back to its default value", OPCHK_PropSetValue, 0, 0, OPINV_PropSetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_prop_set_min", "Set Min Value", "Set property to its minimum value", OPCHK_PropSetValue, 0, 0, OPINV_PropSetMin, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_prop_set_max", "Set Max Value", "Set property to its maximum value", OPCHK_PropSetValue, 0, 0, OPINV_PropSetMax, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_string_set_default", "Set Default Value", "Set default string", OPCHK_StringSetValue, 0, 0, OPINV_PropSetDefault, 0, U'⭯', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_string_get_folder_path", "Get folder Path", "get folder path", OPCHK_StringSetValue, 0, 0, OPINV_StringGetFolderPath, OPMOD_StringGetFolderOrFilePath, U'📁', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_string_get_file_path", "Get folder Path", "get file path", OPCHK_StringSetValue, 0, 0, OPINV_StringGetFilePath, OPMOD_StringGetFolderOrFilePath, U'🖹', LA_ACTUATOR_SYSTEM);
+    
+    laCreateOperatorType("LA_prop_insert_key", "Insert Key Frame", "Insert key frame in the active action", OPCHK_PropInsertKey, 0, 0, OPINV_PropInsertKey, 0, U'🔑', LA_ACTUATOR_SYSTEM);
 
     laCreateOperatorType("LA_sub_put_data_block", "Put Data Block", "Put Pending Data Block Here",
                           OPCHK_SubPutDataBlock, 0, 0, OPINV_SubPutDataBlock, 0, U'🡮', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);

+ 35 - 28
resources/la_properties.c

@@ -860,33 +860,40 @@ void la_RegisterGeneralProps(){
     laKeyMapper *km;
 
     p = la_SetGeneralRoot(&MAIN.GeneralIntSub, "__general_int__", "Genral Int Operations", "Genral Int Operations");
-    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_int_restore_default", U'⭯', 0);
-    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_int_set_max", 0,0);
-    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_int_set_min", 0,0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_prop_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set property to its maximum value", "LA_prop_set_max", 0,0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set property to its minimum value", "LA_prop_set_min", 0,0);
     //laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", U'🛈', 0);
-
+    laAddOperatorProperty(p, "insert_key", "Insert Key Frame", "Insert key frame in the active action", "LA_prop_insert_key", 0,0);
+    
     p = la_SetGeneralRoot(&MAIN.GeneralIntArraySub, "__general_int_arr__", "Genral Int Array Operations", "Genral Int Array Operations");
-    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_int_array_restore_default", U'⭯', 0);
-    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_int_array_set_max", 0,0);
-    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_int_array_set_min", 0,0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_prop_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set property to its maximum value", "LA_prop_set_max", 0,0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set property to its minimum value", "LA_prop_set_min", 0,0);
     //laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", U'🛈', 0);
-
+    laAddOperatorProperty(p, "insert_key", "Insert Key Frame", "Insert key frame in the active action", "LA_prop_insert_key", 0,0);
+    
     p = la_SetGeneralRoot(&MAIN.GeneralFloatSub, "__general_real__", "Genral Float Operations", "Genral Float Operations");
-    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_real_restore_default", U'⭯', 0);
-    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_real_set_max", 0,0);
-    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_real_set_min", 0,0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_prop_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set property to its maximum value", "LA_prop_set_max", 0,0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set property to its minimum value", "LA_prop_set_min", 0,0);
     //laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", U'🛈', 0);
-
+    laAddOperatorProperty(p, "insert_key", "Insert Key Frame", "Insert key frame in the active action", "LA_prop_insert_key", 0,0);
+    
     p = la_SetGeneralRoot(&MAIN.GeneralFloatArraySub, "__general_real_arr__", "Genral Float Array Operations", "Genral Float Array Operations");
-    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_real_array_restore_default", U'⭯', 0);
-    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_real_array_set_max", 0,0);
-    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_real_array_set_min", 0,0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_prop_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set property to its maximum value", "LA_prop_set_max", 0,0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set property to its minimum value", "LA_prop_set_min", 0,0);
     //laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", U'🛈', 0);
-
+    laAddOperatorProperty(p, "insert_key", "Insert Key Frame", "Insert key frame in the active action", "LA_prop_insert_key", 0,0);
+    
     p = la_SetGeneralRoot(&MAIN.GeneralEnumSub, "__general_enum__", "Genral Enum Operations", "Genral Enum Operations");
-    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_enum_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_prop_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "insert_key", "Insert Key Frame", "Insert key frame in the active action", "LA_prop_insert_key", 0,0);
+    
     p = la_SetGeneralRoot(&MAIN.GeneralEnumArraySub, "__general_enum_arr__", "Genral Enum Array Operations", "Genral Enum Array Operations");
-    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_enum_array_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_prop_restore_default", U'⭯', 0);
+    laAddOperatorProperty(p, "insert_key", "Insert Key Frame", "Insert key frame in the active action", "LA_prop_insert_key", 0,0);
     
     p = la_SetGeneralRoot(&MAIN.GeneralStringSub, "__general_string__", "Genral String Operations", "Genral String Operations");
     laAddOperatorProperty(p, "copy", "Copy", "Copy to clipboard", "LA_string_copy", 0,0);
@@ -1445,15 +1452,15 @@ void la_RegisterInternalProps(){
                 laAddEnumItemAs(ep, "BOUNCE", "Bounce", "Play action back and forth", LA_ANIMATION_PLAY_MODE_BOUNCE,U'⮀');
             }
         }
-        p = laAddPropertyContainer("la_animation_channel", "Channel", "Animation channel",0,0,sizeof(laAnimationChannel),0,0,1);{
-            laAddSubGroup(p, "keys", "Keys", "Key Frames", "la_animation_key",0,0,0,-1,0,0,0,0,0,0,offsetof(laAnimationChannel, Keys),0);
-            laAddIntProperty(p, "data_size","Data Size","Data size of the channel",0,0,0,0,0,0,0,0,offsetof(laAnimationChannel,DataSize),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
-            laAddSubGroup(p, "prop", "Property", "Property of this channel", "property_item",0,0,0,offsetof(laAnimationChannel, Prop), 0,0,0,0,0,0,0,LA_UDF_REFER | LA_UDF_IGNORE);
+        p = laAddPropertyContainer("la_animation_channel", "Channel", "Action channel",0,0,sizeof(laActionChannel),0,0,1);{
+            laAddSubGroup(p, "keys", "Keys", "Key Frames", "la_animation_key",0,0,0,-1,0,0,0,0,0,0,offsetof(laActionChannel, Keys),0);
+            laAddIntProperty(p, "data_size","Data Size","Data size of the channel",0,0,0,0,0,0,0,0,offsetof(laActionChannel,DataSize),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+            laAddSubGroup(p, "prop", "Property", "Property of this channel", "property_item",0,0,0,offsetof(laActionChannel, Prop), 0,0,0,0,0,0,0,LA_UDF_REFER | LA_UDF_IGNORE);
             // XXX: Prop needs a string "container.prop" to be able to be able to r/w.
-            laAddSubGroup(p, "for", "For", "Target data block", "any_pointer",0,0,0,offsetof(laAnimationChannel, For), 0,0,0,0,0,0,0,LA_UDF_REFER);
+            laAddSubGroup(p, "for", "For", "Target data block", "any_pointer",0,0,0,offsetof(laActionChannel, For), 0,0,0,0,0,0,0,LA_UDF_REFER);
         }
-        p = laAddPropertyContainer("la_animation_key", "key", "Animation channel",0,0,sizeof(laAnimationKey),0,0,1);{
-            laAddIntProperty(p, "at","At","Frame number of this key frame",0,0,0,0,0,0,0,0,offsetof(laAnimationKey,At),0,0,0,0,0,0,0,0,0,0,0);
+        p = laAddPropertyContainer("la_animation_key", "key", "Action channel",0,0,sizeof(laActionKey),0,0,1);{
+            laAddIntProperty(p, "at","At","Frame number of this key frame",0,0,0,0,0,0,0,0,offsetof(laActionKey,At),0,0,0,0,0,0,0,0,0,0,0);
             // XXX: RAW for r/w.
         }
     }
@@ -1525,9 +1532,9 @@ void la_RegisterInternalProps(){
         laAddFloatProperty(p, "glocation", "Global Location", "Location in global coordinates", 0,"X,Y,Z", 0,0,0,0.1, 0,0,offsetof(tnsObject, GLocation), 0,0,3, 0,0,0,0,0,0,0,LA_READ_ONLY);
         laAddFloatProperty(p, "grotation", "Global Rotation", "Rotation in global coordinates", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsObject, GRotation), 0,0,3, 0,0,0,0,0,0,0,LA_READ_ONLY);
         laAddFloatProperty(p, "gscale", "Global Scale", "Global uniform scale", 0,0,0,0,0,0,0,0,offsetof(tnsObject, GScale), 0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
-        laAddFloatProperty(p, "dlocation", "Delta Location", "XYZ delta transforms", 0,"X,Y,Z", 0,0,0,0.1, 0,0,offsetof(tnsObject, DLocation), 0,0,3,0,0,0,0,tnsset_ObjectDLocationARR,0,0,0);
-        laAddFloatProperty(p, "drotation", "Delta Rotation", "Delta rotation", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsObject, DRotation), 0,0,3,0,0,0,0,tnsset_ObjectDRotationARR,0,0,0);
-        laAddFloatProperty(p, "dscale", "Delta Scale", "Delta scale", 0,0,0,0,0,0,0,0,offsetof(tnsObject, DScale), 0,tnsset_ObjectDScale,0,0,0,0,0,0,0,0,0);
+        laAddFloatProperty(p, "dlocation", "Delta Location", "XYZ delta transforms", 0,"X,Y,Z", 0,0,0,0.1, 0,0,offsetof(tnsObject, DLocation), 0,0,3,0,0,0,0,tnsset_ObjectDLocationARR,0,0,LA_PROP_KEYABLE);
+        laAddFloatProperty(p, "drotation", "Delta Rotation", "Delta rotation", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsObject, DRotation), 0,0,3,0,0,0,0,tnsset_ObjectDRotationARR,0,0,LA_PROP_KEYABLE|LA_PROP_ROTATION);
+        laAddFloatProperty(p, "dscale", "Delta Scale", "Delta scale", 0,0,0,0,0,0,0,0,offsetof(tnsObject, DScale), 0,tnsset_ObjectDScale,0,0,0,0,0,0,0,0,LA_PROP_KEYABLE);
         laAddFloatProperty(p, "global_mat", "Global Matrix", "Global transformation matrix", 0,0,0,0,0,0,0,0,offsetof(tnsObject, GlobalTransform), 0,0,16, 0,0,0,0,0,0,0,LA_READ_ONLY);
         laAddFloatProperty(p, "local_mat", "Local Matrix", "Local transformation matrix", 0,0,0,0,0,0,0,0,offsetof(tnsObject, SelfTransform), 0,0,16, 0,0,0,0,0,0,0,LA_READ_ONLY);
         ep = laAddEnumProperty(p, "rotation_mode", "Rotation Mode", "Rotation Mode Of This Object(e.g. XYZ/XZY/Quaternion...)", 0,0,0,0,0,offsetof(tnsObject, RotationMode), 0,0,0,0,0,0,0,0,0,0);{