*/}}
1
0
Selaa lähdekoodia

Reorder shapes and some animation fixes

YimingWu 1 vuosi sitten
vanhempi
commit
3a20d10381
7 muutettua tiedostoa jossa 120 lisäystä ja 48 poistoa
  1. 4 4
      la_animation.c
  2. 3 3
      la_tns.h
  3. 47 20
      la_tns_kernel.c
  4. 30 6
      la_tns_shape.c
  5. 31 12
      resources/la_modelling.c
  6. 3 3
      resources/la_properties.c
  7. 2 0
      resources/la_widgets_viewers.c

+ 4 - 4
la_animation.c

@@ -172,8 +172,8 @@ int OPMOD_AnimationNewAction(laOperator *a, laEvent *e){
     if(a->ConfirmData->Mode == LA_CONFIRM_CANCEL||a->ConfirmData->Mode == LA_CONFIRM_OK){ if(np) memFree(np); return LA_CANCELED; }
 
     if(a->ConfirmData->Mode == LA_CONFIRM_DATA){
-        if (!np || !np->SelectedHolder){ if(np) free(np); return LA_CANCELED; }
-        laAnimiationNewAction(np->SelectedHolder,0); free(np);
+        if (!np || !np->SelectedHolder){ if(np) memFree(np); return LA_CANCELED; }
+        laAnimiationNewAction(np->SelectedHolder,0); memFree(np);
         return LA_FINISHED;
     }
 
@@ -597,7 +597,7 @@ void la_AnimationActionDrawCanvas(laBoxedTheme *bt, laAction *aa, laUiItem* ui){
             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){
+            for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){ if(!ac->AP){ continue; }
                 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++;
             }
@@ -651,7 +651,7 @@ void la_AnimationActionDrawOverlay(laUiItem *ui, int h){
 void la_RegisterAnimationResources(){
     laPropContainer *pc; laProp *p; laOperatorType *at; laEnumProp *ep;
 
-    at=laCreateOperatorType("LA_animation_new_action", "New Action", "Add a new action",0,0,OPEXT_FreeUserData,OPINV_AnimationNewAction,OPMOD_AnimationNewAction,U'🞦',0);
+    at=laCreateOperatorType("LA_animation_new_action", "New Action", "Add a new action",0,0,0,OPINV_AnimationNewAction,OPMOD_AnimationNewAction,U'🞦',0);
     pc = laDefineOperatorProps(at, 1);
     p = laAddSubGroup(pc, "holder", "Holder", "Action holder to add the new action into", "la_animation_action_holder",
         0, 0, laui_IdentifierOnly, -1, laget_AnimationFirstActionHolder, 0, laget_ListNext, 0, 0, laset_AnimationNewActionSetHolder,0,0);

+ 3 - 3
la_tns.h

@@ -1277,9 +1277,9 @@ void tnsDrawWorld(int W, int H);
 
 tnsMaterial *tnsCreateMaterial(char *Name);
 tnsMaterial *tnsFindMaterial(char *name);
-tnsMaterialSlot* tnsNewMaterialSlot(tnsMeshObject* mo);
-void tnsRemoveMaterialSlot(tnsMeshObject* mo, tnsMaterialSlot* ms);
-void tnsAssignMaterialSlot(tnsMeshObject* mo, tnsMaterialSlot* ms);
+tnsMaterialSlot* tnsNewMaterialSlot(tnsObject* o);
+void tnsRemoveMaterialSlot(tnsObject* o, tnsMaterialSlot* ms);
+void tnsAssignMaterialSlot(tnsObject* o, tnsMaterialSlot* ms);
 
 void tnsRefreshMaterialLibraries();
 void tnsEnsureMaterialShader(tnsMaterial* mat, int Refresh);

+ 47 - 20
la_tns_kernel.c

@@ -4197,35 +4197,62 @@ void tnsRemoveMaterial(tnsMaterial* mat){
     laNodeRack* rr; while(rr=lstPopItem(&mat->Page->Racks)){ laDestroyRack(rr); }
     strSafeDestroy(&mat->Page->Name); memLeave(mat->Page);
     for(tnsObject* o=T->World->AllObjects.pFirst;o;o=o->Item.pNext){
-        if(o->Type!=TNS_OBJECT_MESH) continue; tnsMeshObject* mo=o;
-        for(tnsMaterialSlot* msi=mo->Materials.pFirst;msi;msi=msi->Item.pNext){
-            if(msi->Material==mat){ memAssignRef(msi,&msi->Material,0); }
+        if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o;
+            for(tnsMaterialSlot* msi=mo->Materials.pFirst;msi;msi=msi->Item.pNext){
+                if(msi->Material==mat){ memAssignRef(msi,&msi->Material,0); }
+            }
+        }elif(o->Type==TNS_OBJECT_SHAPE){ tnsShapeObject* so=o;
+            for(tnsMaterialSlot* msi=so->Materials.pFirst;msi;msi=msi->Item.pNext){
+                if(msi->Material==mat){ memAssignRef(msi,&msi->Material,0); }
+            }
         }
     }
     tnsRefreshMaterialLibraries();
     memLeave(mat);
 }
-tnsMaterialSlot* tnsNewMaterialSlot(tnsMeshObject* mo){
-    if(mo->Base.Type!=TNS_OBJECT_MESH) return 0; short nextid=0,found=1;
-    while(found){ found=0;
-        for(tnsMaterialSlot* msi=mo->Materials.pFirst;msi;msi=msi->Item.pNext){
-            if(nextid==msi->Index){ found=1; nextid++; continue; }
+tnsMaterialSlot* tnsNewMaterialSlot(tnsObject* o){
+    if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o; short nextid=0,found=1;
+        while(found){ found=0;
+            for(tnsMaterialSlot* msi=mo->Materials.pFirst;msi;msi=msi->Item.pNext){
+                if(nextid==msi->Index){ found=1; nextid++; continue; }
+            }
+        }
+        tnsMaterialSlot* ms=memAcquire(sizeof(tnsMaterialSlot)); lstAppendItem(&mo->Materials,ms);
+        ms->Index=nextid; memAssignRef(ms,&ms->Parent,mo); memAssignRef(mo,&mo->CurrentMaterial,ms);
+        return ms;
+    }elif(o->Type==TNS_OBJECT_SHAPE){ tnsShapeObject* so=o; short nextid=0,found=1;
+        while(found){ found=0;
+            for(tnsMaterialSlot* msi=so->Materials.pFirst;msi;msi=msi->Item.pNext){
+                if(nextid==msi->Index){ found=1; nextid++; continue; }
+            }
         }
+        tnsMaterialSlot* ms=memAcquire(sizeof(tnsMaterialSlot)); lstAppendItem(&so->Materials,ms);
+        ms->Index=nextid; memAssignRef(ms,&ms->Parent,so); memAssignRef(so,&so->CurrentMaterial,ms);
+        return ms;
     }
-    tnsMaterialSlot* ms=memAcquire(sizeof(tnsMaterialSlot)); lstAppendItem(&mo->Materials,ms);
-    ms->Index=nextid; memAssignRef(ms,&ms->Parent,mo); memAssignRef(mo,&mo->CurrentMaterial,ms);
-    return ms;
 }
-void tnsRemoveMaterialSlot(tnsMeshObject* mo, tnsMaterialSlot* ms){
-    if(mo->Base.Type!=TNS_OBJECT_MESH) return;
-    memAssignRef(mo,&mo->CurrentMaterial,ms->Item.pNext?ms->Item.pNext:ms->Item.pPrev);
-    lstRemoveItem(&mo->Materials,ms); memLeave(ms);
+void tnsRemoveMaterialSlot(tnsObject* o, tnsMaterialSlot* ms){
+    if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o;
+        memAssignRef(mo,&mo->CurrentMaterial,ms->Item.pNext?ms->Item.pNext:ms->Item.pPrev);
+        lstRemoveItem(&mo->Materials,ms); memLeave(ms);
+    }elif(o->Type==TNS_OBJECT_SHAPE){ tnsShapeObject* so=o;
+        memAssignRef(so,&so->CurrentMaterial,ms->Item.pNext?ms->Item.pNext:ms->Item.pPrev);
+        lstRemoveItem(&so->Materials,ms); memLeave(ms);
+    }
 }
-void tnsAssignMaterialSlot(tnsMeshObject* mo, tnsMaterialSlot* ms){
-    if(mo->Mode==TNS_MESH_OBJECT_MODE){
-        for(int i=0;i<mo->totf;i++){ mo->f[i].mat=ms->Index; }
-    }elif(mo->Mode==TNS_MESH_EDIT_MODE){
-        for(tnsMFace* f=mo->mf.pFirst;f;f=f->Item.pNext){ if(f->flags&TNS_MESH_FLAG_SELECTED) f->mat=ms->Index; }
+void tnsAssignMaterialSlot(tnsObject* o, tnsMaterialSlot* ms){
+    if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o;
+        if(mo->Mode==TNS_MESH_OBJECT_MODE){
+            for(int i=0;i<mo->totf;i++){ mo->f[i].mat=ms->Index; }
+        }elif(mo->Mode==TNS_MESH_EDIT_MODE){
+            for(tnsMFace* f=mo->mf.pFirst;f;f=f->Item.pNext){ if(f->flags&TNS_MESH_FLAG_SELECTED) f->mat=ms->Index; }
+        }
+    }elif(o->Type==TNS_OBJECT_SHAPE){ tnsShapeObject* so=o;
+        if(so->Mode==TNS_MESH_OBJECT_MODE){
+            for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ s->mat=ms->Index; }
+        }elif(so->Mode==TNS_MESH_EDIT_MODE){
+            for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ if(tnsShapePointAnySelected(s)) s->mat=ms->Index; }
+        }
     }
 }
 

+ 30 - 6
la_tns_shape.c

@@ -239,7 +239,7 @@ void tnsInitShapeSquare(tnsShapeObject* so, real size){
     tnsShapeSetClosed(s,1,0); tnsShapeRefreshIndex(so);
 }
 
-void tns_DrawShape(tnsShape* s, real* override_color, int DrawEdit, real PointScale){
+void tns_DrawShape(tnsShape* s, tnsMaterial* mat, real* override_color, int DrawEdit, real PointScale){
     if(!s->Points.pFirst) return; int HasSelection=0; int closed=(s->flags&TNS_SHAPE_CLOSED);
     NVGcontext* vg=MAIN.CurrentWindow->nvg;
     if(DrawEdit==2){
@@ -277,7 +277,7 @@ void tns_DrawShape(tnsShape* s, real* override_color, int DrawEdit, real PointSc
         nvgClosePath(vg);
         nvgPathWinding(vg,(s->flags&TNS_SHAPE_HOLE)?NVG_HOLE:NVG_SOLID);
         if(!(s->flags&TNS_SHAPE_HOLE)){
-            nvgFillColor(vg, override_color?nvgRGBAf(LA_COLOR4(override_color)):nvgRGBAf(0.8,0.8,0.8,1));
+            nvgFillColor(vg, override_color?nvgRGBAf(LA_COLOR4(override_color)):(mat?nvgRGBAf(LA_COLOR4(mat->Color)):nvgRGBAf(0.8,0.8,0.8,1)));
         }
     }
     if(DrawEdit || (!closed)){
@@ -323,16 +323,19 @@ void tnsDrawShapeObjectShapes(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de,
         nvgScale(vg,sca[0],-sca[1]); nvgRotate(vg,rot[2]);
     }
     if(DrawEdit!=2){ int begun=0; int ishole=0,nexthole=0;
-        for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
+        for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ tnsMaterial* mat=0;
+            if(de->DisplayMode==LA_CANVAS_DISPLAY_MATERIAL){
+                for(tnsMaterialSlot* ms=so->Materials.pFirst;ms;ms=ms->Item.pNext){ if(s->mat==ms->Index){ mat=ms->Material; break; } }
+            }
             if(!begun){ begun=1; nvgBeginPath(vg); }
             ishole=s->flags&TNS_SHAPE_HOLE; tnsShape* ns=s->Item.pNext; nexthole=ns?(ns->flags&TNS_SHAPE_HOLE):0;
-            tns_DrawShape(s,override_color,0,de->PointScale/sca[0]);
-            if((!ns) || (ishole&&(!nexthole))){ nvgFill(vg); begun=0; }
+            tns_DrawShape(s,mat,override_color,0,de->PointScale/sca[0]);
+            if(!nexthole /*(!ns) || (ishole &&(!nexthole))*/){ nvgFill(vg); begun=0; }
         }
     }
     if(DrawEdit||so->Mode==TNS_MESH_EDIT_MODE){
         for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
-            tns_DrawShape(s,override_color,DrawEdit?DrawEdit:so->Mode==TNS_MESH_EDIT_MODE,de->PointScale/sca[0]);
+            tns_DrawShape(s,0,override_color,DrawEdit?DrawEdit:so->Mode==TNS_MESH_EDIT_MODE,de->PointScale/sca[0]);
         }
     }
     nvgRestore(vg);
@@ -478,6 +481,26 @@ int OPINV_SetShapeHole(laOperator *a, laEvent *e){
     }
     return LA_FINISHED;
 }
+int OPINV_ReorderShape(laOperator *a, laEvent *e){
+    laCanvasExtra* ex=a->This->EndInstance; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0;
+    if(!root || !root->Active || root->Active->Type!=TNS_OBJECT_SHAPE) return LA_FINISHED;
+    tnsShapeObject* so=root->Active; int ran=0;
+
+    char* mode=strGetArgumentString(a->ExtraInstructionsP,"direction");
+    int set=0; if(strSame(mode,"UP")){ set=1; }elif(strSame(mode,"DOWN")){ set=0; }
+
+    tnsShape* ns;
+    for(tnsShape*s=so->Shapes.pFirst;s;s=ns){ ns=s->Item.pNext;
+        if((!tnsShapePointAnySelected(s))||s->flags&TNS_MESH_FLAG_PICKED) continue;
+        if(set) lstMoveUp(&so->Shapes,s); else lstMoveDown(&so->Shapes,s); s->flags|=TNS_MESH_FLAG_PICKED; ran=1;
+    }
+    if(ran){ tnsShapeClearExtraFlags(so);
+        laRecordInstanceDifferences(so,"tns_shape_object"); laPushDifferences("Reorder shapes",TNS_HINT_GEOMETRY);
+        laNotifyUsers("tns.world");
+    }
+    return LA_FINISHED;
+}
 void la_RegisterShapeOperators(){
     laPropContainer *pc; laProp *p;
     laOperatorType *at; laEnumProp *ep;
@@ -486,4 +509,5 @@ void la_RegisterShapeOperators(){
     at->UiDefine=laui_SetPointHandle;
     at=laCreateOperatorType("M_set_shape_closed", "Set Shape Closed", "Set shape closed or open",OPCHK_IsAnyPointSelected,0,0,OPINV_SetShapeClosed,0,0,0);
     at=laCreateOperatorType("M_set_shape_hole", "Set Shape Hole", "Set shape as hole or fill",OPCHK_IsAnyPointSelected,0,0,OPINV_SetShapeHole,0,0,0);
+    at=laCreateOperatorType("M_reorder_shape", "Reorder shape", "Reorder shapes (move up/down in the stack)",OPCHK_IsAnyPointSelected,0,0,OPINV_ReorderShape,0,0,0);
 }

+ 31 - 12
resources/la_modelling.c

@@ -1929,12 +1929,20 @@ int OPINV_RemoveRootObject(laOperator *a, laEvent *e){
 
 int OPINV_NewMaterial(laOperator *a, laEvent *e){
     tnsMaterial* mat=tnsCreateMaterial("Material"); laNotifyUsers("tns.world.materials");
-    if(a->This && a->This->EndInstance && la_EnsureSubTarget(a->This->LastPs->p,a->This->EndInstance)==TNS_PC_OBJECT_MESH){
+    if(!a->This && a->This->EndInstance) return;
+    laPropContainer* pc=la_EnsureSubTarget(a->This->LastPs->p,a->This->EndInstance);
+    if(pc==TNS_PC_OBJECT_MESH){
         tnsMeshObject* mo=a->This->EndInstance; if(mo->CurrentMaterial){
             memAssignRef(mo->CurrentMaterial,&mo->CurrentMaterial->Material,mat);
             tnsInvalidateMeshBatch(mo);
             laRecordInstanceDifferences(mo,"tns_mesh_object"); laNotifyInstanceUsers(mo);
         }
+    }elif(pc==TNS_PC_OBJECT_SHAPE){
+        tnsShapeObject* so=a->This->EndInstance; if(so->CurrentMaterial){
+            memAssignRef(so->CurrentMaterial,&so->CurrentMaterial->Material,mat);
+            tnsInvalidateMeshBatch(so);
+            laRecordInstanceDifferences(so,"tns_shape_object"); laNotifyInstanceUsers(so);
+        }
     }
     laDetachedTrySet("material",mat);
     laRecordDifferences(0,"tns.world.materials"); laPushDifferences("New material",0);
@@ -1953,11 +1961,13 @@ int OPINV_RemoveMaterial(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 int OPCHK_NewMaterialSlot(laPropPack *This, laStringSplitor *ss){
-    if(This && This->EndInstance){ if(la_EnsureSubTarget(This->LastPs->p,This->EndInstance)==TNS_PC_OBJECT_MESH) return 1; } return 0;
+    if(This && This->EndInstance){ laPropContainer* pc=la_EnsureSubTarget(This->LastPs->p,This->EndInstance);
+        if(pc==TNS_PC_OBJECT_MESH||pc==TNS_PC_OBJECT_SHAPE) return 1;
+    } return 0;
 }
 int OPINV_NewMaterialSlot(laOperator *a, laEvent *e){
-    if(!a->This || !a->This->EndInstance){ return LA_FINISHED; } tnsMeshObject* mo=a->This->EndInstance;
-    tnsNewMaterialSlot(mo); laNotifyInstanceUsers(mo);
+    if(!a->This || !a->This->EndInstance){ return LA_FINISHED; } tnsObject* o=a->This->EndInstance;
+    tnsNewMaterialSlot(o); laNotifyInstanceUsers(o);
     laRecordDifferences(0,"tns.world.objects"); laPushDifferences("New material slot",0);
     return LA_FINISHED;
 }
@@ -1972,19 +1982,28 @@ int OPINV_RemoveMaterialSlot(laOperator *a, laEvent *e){
 }
 
 int OPCHK_AssignMaterialSlot(laPropPack *This, laStringSplitor *ss){
-    if(This && This->EndInstance){
-        if(la_EnsureSubTarget(This->LastPs->p,This->EndInstance)==TNS_PC_OBJECT_MESH){
+    if(This && This->EndInstance){ laPropContainer* pc=la_EnsureSubTarget(This->LastPs->p,This->EndInstance);
+        if(pc==TNS_PC_OBJECT_MESH){
             tnsMeshObject* mo=This->EndInstance; if(mo->Mode==TNS_MESH_EDIT_MODE && mo->CurrentMaterial) return 1;
+        }elif(pc==TNS_PC_OBJECT_SHAPE){
+            tnsShapeObject* so=This->EndInstance; if(so->Mode==TNS_MESH_EDIT_MODE && so->CurrentMaterial) return 1;
         }
     } return 0;
 }
 int OPINV_AssignMaterialSlot(laOperator *a, laEvent *e){
-    if(!a->This || !a->This->EndInstance){ return LA_FINISHED; }
-    tnsMeshObject* mo=a->This->EndInstance; tnsMaterialSlot* ms=mo->CurrentMaterial;
-    if(mo->Mode!=TNS_MESH_EDIT_MODE || !ms) return LA_FINISHED;
-    tnsAssignMaterialSlot(mo,ms); tnsInvalidateMeshBatch(mo);
-    laNotifyInstanceUsers(mo); laNotifyUsers("tns.world");
-    laRecordInstanceDifferences(mo,"tns_mesh_object"); laPushDifferences("Assign material slot",0);
+    if(!a->This || !a->This->EndInstance){ return LA_FINISHED; } tnsObject* o=a->This->EndInstance;
+    laPropContainer* pc=la_EnsureSubTarget(a->This->LastPs->p,a->This->EndInstance);
+    if(pc==TNS_PC_OBJECT_MESH){ tnsMeshObject* mo=o;
+        tnsMaterialSlot* ms=mo->CurrentMaterial;
+        if(mo->Mode!=TNS_MESH_EDIT_MODE || !ms) return LA_FINISHED;
+        tnsAssignMaterialSlot(mo,ms); tnsInvalidateMeshBatch(mo); laRecordInstanceDifferences(mo,"tns_mesh_object");
+    }elif(pc==TNS_PC_OBJECT_SHAPE){ tnsShapeObject* so=o;
+        tnsMaterialSlot* ms=so->CurrentMaterial;
+        if(so->Mode!=TNS_MESH_EDIT_MODE || !ms) return LA_FINISHED;
+        tnsAssignMaterialSlot(so,ms); laRecordInstanceDifferences(so,"tns_shape_object");
+    }
+    laNotifyInstanceUsers(o); laNotifyUsers("tns.world");
+     laPushDifferences("Assign material slot",0);
     return LA_FINISHED;
 }
 int OPCHK_RefreshMaterialShader(laPropPack *This, laStringSplitor *ss){

+ 3 - 3
resources/la_properties.c

@@ -1172,7 +1172,6 @@ void la_RegisterTNSProps(){
         laAddSubGroup(p, "in_root", "In Root", "Root object of this object", "tns_object",0,0,0,offsetof(tnsObject, InRoot), 0,0,0,0,0,0,0,LA_UDF_REFER);
         laAddSubGroup(p, "parent", "Parent", "Object parent", "tns_object",0,0,0,offsetof(tnsObject, ParentObject), 0,0,0,0,0,0,0,LA_UDF_REFER);
         laAddSubGroup(p, "children", "Children", "The Children Of This Object", "tns_child_object",0,0,0,-1, 0,0,0,0,0,0,offsetof(tnsObject, ChildObjects), 0);
-        laAddSubGroup(p, "__actions__", "Actions", "Animation actions", "la_animation_action",0,0,0,-1,0,laget_CurrentAnimationAction,0,laset_CurrentAnimationAction,0,0,offsetof(tnsObject, Actions), 0);
         laAddSubGroup(p, "drivers", "Drivers", "Driver page collection","la_driver_collection",0,0,0,offsetof(tnsObject,Drivers),0,0,0,0,0,0,0,LA_UDF_SINGLE|LA_HIDE_IN_SAVE);
         laAddOperatorProperty(p, "add_driver_page", "Add Page", "Add a driver page","LA_add_driver_page",'+',0);
         laAddSubGroup(p, "as_mesh", "As Mesh", "As mesh object", "tns_mesh_object",0,0,0,-1,0,tnsget_ObjectAsMesh,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY|LA_UDF_IGNORE);
@@ -1183,6 +1182,7 @@ void la_RegisterTNSProps(){
         TNS_PC_OBJECT_ROOT=p;
         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);
         laAddSubGroup(p, "base", "Base", "Object base", "tns_object",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
+        laAddSubGroup(p, "__actions__", "Actions", "Animation actions", "la_animation_action",0,0,0,-1,0,laget_CurrentAnimationAction,0,laset_CurrentAnimationAction,0,0,offsetof(tnsObject, Actions), 0);
         laAddSubGroup(p, "active_camera", "Active Camera", "Active camera of this root object", "tns_object",0,0,0,offsetof(tnsRootObject, ActiveCamera),0,0,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY);
         ep = laAddEnumProperty(p, "is_2d", "Is 2D", "Is 2D root object", 0,0,0,0,0,offsetof(tnsRootObject, Is2D), 0,tnsset_RootObjectIs2D,0,0,0,0,0,0,0,0);{
             laAddEnumItemAs(ep, "3D", "3D", "Root object is in 3D", 0, 0);
@@ -1208,7 +1208,7 @@ void la_RegisterTNSProps(){
             laAddEnumItemAs(ep, "BC", "Bottom Center", "Hook to bottom center", TNS_INSTANCER_HOOK_BC, L'🡣');
             laAddEnumItemAs(ep, "BR", "Bottom Right", "Hook to bottom right", TNS_INSTANCER_HOOK_BR, L'🡦');
         }
-        laAddFloatProperty(p, "hook_offset", "Hook Offset", "Offset of the 2d hook point", 0,0,"X,Y",0,0,0,0,0,offsetof(tnsInstancer, HookOffset),0,0,2,0,0,0,0,tnssetarr_InstancerHookOffset,0,0,0);
+        laAddFloatProperty(p, "hook_offset", "Hook Offset", "Offset of the 2d hook point", 0,0,"X,Y",0,0,0,0,0,offsetof(tnsInstancer, HookOffset),0,0,2,0,0,0,0,tnssetarr_InstancerHookOffset,0,0,LA_PROP_KEYABLE);
     }
     p = laAddPropertyContainer("tns_mesh_object", "Mesh Object", "Mesh object", 0,tnsui_MeshObjectProperties,sizeof(tnsMeshObject), tnspost_Object, 0,2);{
         laPropContainerExtraFunctions(p,0,0,tnstouched_Object,0/*tnspropagate_Object*/,0);
@@ -1283,7 +1283,7 @@ void la_RegisterTNSProps(){
         laAddSubGroup(p, "materials", "Materials", "Material slots in this mesh object", "tns_material_slot",0,0,0,-1,0,tnsget_ActiveMaterialSlot,0,tnsset_ActiveMaterialSlot,0,0,offsetof(tnsShapeObject, Materials),0);
         laAddOperatorProperty(p,"add_material_slot","Add Material Slot","Add a material slot into this object","M_new_material_slot",L'+',0);
         laAddOperatorProperty(p,"add_material","Add Material","Add a new material to this material slot","M_new_material",'+',0);
-        //laAddOperatorProperty(p,"assign_material_slot","Assign Material Slot","Assign faces to a current slot","M_assign_material_slot",L'🖌',0);
+        laAddOperatorProperty(p,"assign_material_slot","Assign Material Slot","Assign shapes to a current slot","M_assign_material_slot",L'🖌',0);
     }
     
     p = laAddPropertyContainer("tns_mvert", "MVert", "MMesh vert", 0,0,sizeof(tnsMVert), 0,0,0);{

+ 2 - 0
resources/la_widgets_viewers.c

@@ -1228,4 +1228,6 @@ void la_RegisterUiTypesViewerWidgets(){
     laAssignNewKey(km, 0, "M_set_shape_closed", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'q', 0);
     laAssignNewKey(km, 0, "M_set_shape_closed", LA_KM_SEL_UI_EXTRA, LA_KEY_SHIFT, LA_KEY_DOWN, 'q', "reset=TRUE");
     laAssignNewKey(km, 0, "M_set_shape_hole", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'n', 0);
+    laAssignNewKey(km, 0, "M_reorder_shape", LA_KM_SEL_UI_EXTRA, LA_KEY_CTRL, LA_KEY_DOWN, LA_KEY_ARRDOWN, "direction=DOWN");
+    laAssignNewKey(km, 0, "M_reorder_shape", LA_KM_SEL_UI_EXTRA, LA_KEY_CTRL, LA_KEY_DOWN, LA_KEY_ARRUP, "direction=UP");
 }