*/}}
Ver código fonte

Shape object basics

YimingWu 8 meses atrás
pai
commit
171ae2c847
8 arquivos alterados com 196 adições e 12 exclusões
  1. 1 0
      la_interface.h
  2. 3 0
      la_kernel.c
  3. 31 0
      la_tns.h
  4. 1 0
      la_tns_kernel.c
  5. 84 0
      la_tns_shape.c
  6. 27 3
      resources/la_modelling.c
  7. 43 7
      resources/la_properties.c
  8. 6 2
      resources/la_widgets_viewers.c

+ 1 - 0
la_interface.h

@@ -611,6 +611,7 @@ STRUCTURE(laWindow){
     SYSGLCONTEXT glc;
     int GLDebugNeedsUpdate;
     GLuint vao;
+    struct NVGcontext* nvg;
 #ifdef _WIN32
     HDC hdc;
 #endif

+ 3 - 0
la_kernel.c

@@ -494,6 +494,8 @@ int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){
     glGenVertexArrays(1,&window->vao); tnsBindVertexArray(window->vao);
     la_SetupWindowGLStates(window);
 
+    window->nvg=nvgCreateGL3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS);
+
     window->OutputShowStripes=1; window->Redraw=1;
     window->GLDebugNeedsUpdate=1;
     window->UseComposing=0; window->ComposingGamma=1.0; window->ComposingBlackpoint=0.0;
@@ -502,6 +504,7 @@ int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){
 };
 
 int la_DestroySystemWindow(laWindow* wnd){
+    nvgDeleteGL3(wnd->nvg);
 #ifdef __linux__
     la_DestroySystemWindowX11(wnd);
 #endif

+ 31 - 0
la_tns.h

@@ -445,6 +445,7 @@ typedef struct _tnsObject tnsObject;
 #define TNS_OBJECT_CAMERA (1<<1)
 #define TNS_OBJECT_LIGHT  (1<<2)
 #define TNS_OBJECT_MESH   (1<<3)
+#define TNS_OBJECT_SHAPE  (1<<4)
 
 #define TNS_OBJECT_FLAGS_SELECTED (1<<0)
 #define TNS_OBJECT_FLAGS_PLAY_DUPLICATE (1<<1)
@@ -703,6 +704,7 @@ extern laPropContainer* TNS_PC_OBJECT_INSTANCER;
 extern laPropContainer* TNS_PC_OBJECT_CAMERA;
 extern laPropContainer* TNS_PC_OBJECT_LIGHT;
 extern laPropContainer* TNS_PC_OBJECT_MESH;
+extern laPropContainer* TNS_PC_OBJECT_SHAPE;
 extern laPropContainer* TNS_PC_OBJECT_ROOT;
 extern laPropContainer* TNS_PC_MATERIAL;
 extern laPropContainer* TNS_PC_MATERIAL_SLOT;
@@ -724,6 +726,32 @@ STRUCTURE(tnsMaterialSlot){
     short Index;
 };
 
+STRUCTURE(tnsSPoint){
+    laListItem Item;
+    tnsVector2d p,dl,dr;
+    int flags;
+};
+STRUCTURE(tnsShape){
+    laListItem Item;
+    laListHandle Points;
+    int flags;
+    short mat;
+};
+
+STRUCTURE(tnsShapeObject){
+    tnsObject Base;
+
+    laListHandle Shapes;
+    
+    tnsBatch *Batch;
+    tnsBatch *ExtraBatch;
+
+    tnsMaterialSlot* CurrentMaterial;
+    laListHandle Materials;
+
+    int Mode;
+};
+
 STRUCTURE(tnsMeshObject){
     tnsObject Base;
 
@@ -1079,6 +1107,8 @@ tnsObject *tnsCreateInstancer(tnsObject *under, char *Name, real AtX, real AtY,
 tnsLight *tnsCreateLight(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real Strength, int UniDirectional);
 tnsMeshObject *tnsCreateMeshEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ);
 tnsMeshObject *tnsCreateMeshPlane(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size);
+tnsShapeObject *tnsCreateShapeEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ);
+tnsShapeObject *tnsCreateShapeSquare(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size);
 
 int tnsMergeMeshObjects(tnsMeshObject* into, tnsMeshObject* mo);
 tnsMeshObject* tnsDuplicateMeshObject(tnsMeshObject* from);
@@ -1144,6 +1174,7 @@ void tnsInvalidateMeshBatch(tnsMeshObject* mo);
 void tnsRegenerateMeshBatch(tnsMeshObject* mo);
 void tnsEnsureMeshBatch(tnsMeshObject* mo);
 void tnsEvaluateMeshObject(tnsMeshObject* mo, tnsEvaluateData* ed);
+void tnsEvaluateShapeObject(tnsShapeObject* so, tnsEvaluateData* ed);
 
 void la_RegisterModellingOperators();
 

+ 1 - 0
la_tns_kernel.c

@@ -3811,6 +3811,7 @@ void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
         if(ed->SceneEvaluateMode){ ed->Scene->CurrentParent=CP; ed->Scene->CurrentChild=CC;}
         break;
     case TNS_OBJECT_CAMERA: tnsDrawCamera(o); break;
+    case TNS_OBJECT_SHAPE: tnsEvaluateShapeObject(o,ed); break;
     default: tnsEvaluateEmptyObject(o,ed); break;
     }
 }

+ 84 - 0
la_tns_shape.c

@@ -0,0 +1,84 @@
+/*
+* LaGUI: A graphical application framework.
+* Copyright (C) 2022-2023 Wu Yiming
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "la_5.h"
+#include <math.h>
+
+extern LA MAIN;
+extern tnsMain *T;
+
+tnsShape* tnsNewShape(tnsShapeObject* so){
+    tnsShape* s=memAcquireSimple(sizeof(tnsShape));
+    lstAppendItem(&so->Shapes,s); return s;
+}
+tnsSPoint* tnsNewSPoint(tnsShape* s,real x, real y,real ldx,real ldy, real rdx,real rdy){
+    tnsSPoint* sp=memAcquireSimple(sizeof(tnsSPoint));
+    tnsVectorSet2(sp->p,x,y); tnsVectorSet2(sp->dl,ldx,ldy); tnsVectorSet2(sp->dr,rdx,rdy);
+    lstAppendItem(&s->Points,sp); return sp;
+}
+
+void tnsInitShapeSquare(tnsShapeObject* so, real size){
+    tnsShape* s=tnsNewShape(so);
+    tnsNewSPoint(s,-size,-size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
+    tnsNewSPoint(s,-size,size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
+    tnsNewSPoint(s,size,size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
+    tnsNewSPoint(s,size,-size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
+}
+
+void tns_DrawShape(tnsShape* s, real* override_color){
+    if(!s->Points.pFirst) return;
+    NVGcontext* vg=MAIN.CurrentWindow->nvg; nvgBeginPath(vg);
+    tnsSPoint* sp1=s->Points.pFirst; nvgMoveTo(vg,sp1->p[0],sp1->p[1]);
+    for(tnsSPoint* sp=sp1->Item.pNext;sp;sp=sp->Item.pNext){
+        nvgLineTo(vg,sp->p[0],sp->p[1]);
+    }
+	nvgFillColor(vg, override_color?nvgRGBA(LA_COLOR4(override_color)):nvgRGBAf(0.8,0.8,0.8,1));
+	nvgFill(vg);
+}
+void tnsDrawShapeObject(tnsEvaluatedInstance* ei,la3DObjectDrawExtra* de){
+    tnsShapeObject* so=ei->Object;
+    for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
+        tns_DrawShape(s,0);
+    }
+}
+void tnsDrawShapeObjectSelectionID(tnsEvaluatedInstance* ei, void* unused){
+    tnsShapeObject* so=ei->Object;
+    int i=ei->InstanceSelectionID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i);
+    for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
+        tns_DrawShape(s,color);
+    }
+}
+
+void tnsEvaluateShapeObject(tnsShapeObject* so, tnsEvaluateData* ed){
+    tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObject,TNS_EVAL_LAYER_SOLID,0,0,0);
+    if(ed->FillSelectionID){
+        tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,so->Base.SelectID);
+    }
+}
+
+tnsShapeObject *tnsCreateShapeEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
+    tnsShapeObject *so = memAcquireHyper(sizeof(tnsShapeObject));
+    tnsInitObjectBase(&so->Base, under, Name, TNS_OBJECT_SHAPE, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
+    return so;
+}
+tnsShapeObject *tnsCreateShapeSquare(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size){
+    tnsShapeObject *so=tnsCreateShapeEmpty(under, Name, AtX, AtY, AtZ);
+    tnsInitShapeSquare(so, size);
+    return so;
+}
+

+ 27 - 3
resources/la_modelling.c

@@ -1237,6 +1237,7 @@ int OPINV_Subdiv(laOperator *a, laEvent *e){
 
 #define LA_ADD_CTX_OBJECT 0
 #define LA_ADD_CTX_MESH   1
+#define LA_ADD_CTX_SHAPE  2
 STRUCTURE(laObjectAddData){
     int Context;
 };
@@ -1253,9 +1254,11 @@ int OPINV_Add(laOperator *a, laEvent *e){
             no=tnsCreateMeshPlane(root, "Plane",0,0,0,1); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
         elif(strSame(str,"INSTANCER")){ tnsDeselectAllObjects(root);
             no=tnsCreateInstancer(root, "Instancer",0,0,0); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
+        elif(strSame(str,"SQUARE")){ tnsDeselectAllObjects(root);
+            no=tnsCreateShapeSquare(root, "Square",0,0,0,10); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
         else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
         if(ran){ laRecordAndPush(0,"tns.world","Add object",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world"); }
-    }else{ ad->Context=LA_ADD_CTX_MESH;
+    }elif(mo->Base.Type==TNS_OBJECT_MESH && mo->Mode!=TNS_MESH_EDIT_MODE){ ad->Context=LA_ADD_CTX_MESH;
         if(strSame(str,"PLANE")){
             tnsMMeshDeselectAll(mo); tnsAddMMeshPlane(mo, 1); tnsMMeshEnsureSelection(mo,ex->SelectMode); ran=1;
         }else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
@@ -1263,6 +1266,15 @@ int OPINV_Add(laOperator *a, laEvent *e){
             tnsMMeshRefreshIndex(mo); tnsInvalidateMeshBatch(mo); 
             laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Add primitives", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
         }
+    }elif(mo->Base.Type==TNS_OBJECT_SHAPE && mo->Mode!=TNS_MESH_EDIT_MODE){ ad->Context=LA_ADD_CTX_SHAPE;
+        if(strSame(str,"SQUARE")){
+            //stuff
+            ran=1;
+        }else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
+        if(ran){
+            //stuff
+            laRecordInstanceDifferences(mo, "tns_shape_object"); laPushDifferences("Add primitives", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
+        }
     }
     return LA_FINISHED;
 }
@@ -1272,10 +1284,21 @@ void laui_Add(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extr
     laUiItem* b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(LA_ADD_CTX_OBJECT)));{
         laShowLabel(uil,c,"Empty",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
         laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=INSTANCER;text=Instancer",0,0);
+        laShowLabel(uil,c,"Primitives",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=PLANE;text=Plane",0,0);
+        laShowLabel(uil,c,"Shapes",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=SQUARE;text=Square",0,0);
     }laEndCondition(uil,b);
 
-    laShowLabel(uil,c,"Primitives",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
-    laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=PLANE;text=Plane",0,0);
+    b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(LA_ADD_CTX_MESH)));{
+        laShowLabel(uil,c,"Primitives",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=PLANE;text=Plane",0,0);
+    }laEndCondition(uil,b);
+
+    b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(LA_ADD_CTX_SHAPE)));{
+        laShowLabel(uil,c,"Shapes",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=SQUARE;text=Square",0,0);
+    }laEndCondition(uil,b);
 }
 
 int OPINV_Separate(laOperator *a, laEvent *e){
@@ -1753,6 +1776,7 @@ void la_RegisterModellingOperators(){
     p=laAddEnumProperty(pc,"context","Context","Context of adding",0,0,0,0,0,offsetof(laObjectAddData,Context),0,0,0,0,0,0,0,0,0,0);
     laAddEnumItemAs(p,"OBJECT","Object","Object context",LA_ADD_CTX_OBJECT,0);
     laAddEnumItemAs(p,"MESH","Mesh","Mesh context",LA_ADD_CTX_MESH,0);
+    laAddEnumItemAs(p,"SHAPE","Shape","Shape context",LA_ADD_CTX_SHAPE,0);
 
     laCreateOperatorType("M_separate", "Separate", "Separate mesh parts", 0, 0, 0, OPINV_Separate, 0, 0, 0);
     laCreateOperatorType("M_combine", "Combine", "Combine mesh objects", 0, 0, 0, OPINV_Combine, 0, 0, 0);

+ 43 - 7
resources/la_properties.c

@@ -900,14 +900,19 @@ void tnsget_MaterialSlotname(tnsMaterialSlot* ms, char *result, char** here){
     }
     sprintf(result,"%d: %s",ms->Index,transLate("<Default Material>"));
 }
-tnsMaterialSlot* tnsget_FirstMaterialSlot(tnsMeshObject* mo, void* unused){
-    return mo->Materials.pFirst;
+tnsMaterialSlot* tnsget_FirstMaterialSlot(tnsObject* o, void* unused){
+    if(o->Type==TNS_OBJECT_MESH) return ((tnsMeshObject*)o)->Materials.pFirst;
+    if(o->Type==TNS_OBJECT_SHAPE) return ((tnsShapeObject*)o)->Materials.pFirst;
+    return 0;
 }
-tnsMaterialSlot* tnsget_ActiveMaterialSlot(tnsMeshObject* mo){
-    return mo->CurrentMaterial;
+tnsMaterialSlot* tnsget_ActiveMaterialSlot(tnsObject* o){
+    if(o->Type==TNS_OBJECT_MESH) return ((tnsMeshObject*)o)->CurrentMaterial;
+    if(o->Type==TNS_OBJECT_SHAPE) return ((tnsShapeObject*)o)->CurrentMaterial;
+    return 0;
 }
-void tnsset_ActiveMaterialSlot(tnsMeshObject* mo, tnsMaterialSlot* ms){
-    memAssignRef(mo,&mo->CurrentMaterial,ms);
+void tnsset_ActiveMaterialSlot(tnsObject* o, tnsMaterialSlot* ms){
+    if(o->Type==TNS_OBJECT_MESH) return memAssignRef(o,&((tnsMeshObject*)o)->CurrentMaterial,ms);
+    if(o->Type==TNS_OBJECT_SHAPE) return memAssignRef(o,&((tnsShapeObject*)o)->CurrentMaterial,ms);
 }
 tnsMaterial* tnsget_FirstMaterial(void* unused1, void* unused2){
     return T->World->Materials.pFirst;
@@ -923,6 +928,7 @@ laPropContainer* tnsget_ObjectType(tnsObject* o){
     case TNS_OBJECT_MESH:      return TNS_PC_OBJECT_MESH;
     case TNS_OBJECT_LIGHT:     return TNS_PC_OBJECT_LIGHT;
     case TNS_OBJECT_ROOT:      return TNS_PC_OBJECT_ROOT;
+    case TNS_OBJECT_SHAPE:     return TNS_PC_OBJECT_SHAPE;
     default: return TNS_PC_OBJECT_GENERIC;
     }
 }
@@ -957,6 +963,7 @@ laPropContainer* TNS_PC_OBJECT_INSTANCER;
 laPropContainer* TNS_PC_OBJECT_CAMERA;
 laPropContainer* TNS_PC_OBJECT_LIGHT;
 laPropContainer* TNS_PC_OBJECT_MESH;
+laPropContainer* TNS_PC_OBJECT_SHAPE;
 laPropContainer* TNS_PC_OBJECT_ROOT;
 laPropContainer* TNS_PC_MATERIAL;
 laPropContainer* TNS_PC_MATERIAL_SLOT;
@@ -1234,7 +1241,23 @@ void la_RegisterTNSProps(){
             laAddEnumItem(ep, "orthographic", "Orthographic", "Camera in orthographic view", 0);
         }
     }
-
+    p = laAddPropertyContainer("tns_shape_object", "Shape Object", "Shape object", 0,tnsui_MeshObjectProperties,sizeof(tnsShapeObject), tnspost_Object, 0,2);{
+        laPropContainerExtraFunctions(p,0,0,tnstouched_Object,0/*tnspropagate_Object*/,0);
+        TNS_PC_OBJECT_SHAPE=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);
+        ep = laAddEnumProperty(p, "mode", "Mode", "Shape object mode", 0,0,0,0,0,offsetof(tnsShapeObject, Mode), 0,0,0,0,0,0,0,0,0,0);{
+            laAddEnumItemAs(ep, "OBJECT", "Object", "Object mode", TNS_MESH_OBJECT_MODE, 0);
+            laAddEnumItemAs(ep, "EDIT", "Edit", "Edit mode", TNS_MESH_EDIT_MODE, 0);
+        }
+        laAddSubGroup(p, "shapes", "Shapes", "Shapes inside of the object", "tns_shape",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsShapeObject, Shapes), 0);
+        laAddSubGroup(p, "current_material", "Current Material", "Current material slot in this object", "tns_material_slot",0,0,0,offsetof(tnsShapeObject, CurrentMaterial),tnsget_FirstMaterialSlot,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
+        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);
+    }
+    
     p = laAddPropertyContainer("tns_mvert", "MVert", "MMesh vert", 0,0,sizeof(tnsMVert), 0,0,0);{
         laAddFloatProperty(p, "p", "Position", "Position", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsMVert, p),0,0,3,0,0,0,0,0,0,0,0);
         laAddFloatProperty(p, "n", "Normal", "Normal", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsMVert, n),0,0,3,0,0,0,0,0,0,0,0);
@@ -1255,6 +1278,7 @@ void la_RegisterTNSProps(){
         laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsMFace, flags),0,0,0,0,0,0,0,0,0,0,0);
         laAddSubGroup(p, "l", "Loop", "Loop", "tns_loop",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsMFace, l),0);
         laAddIntProperty(p,"looplen","Loop Length","Loop length",0,0,0,0,0,0,0,0,offsetof(tnsMFace, looplen),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY)->ElementBytes=2;
+        laAddIntProperty(p,"mat","Material","Material of this face",0,0,0,0,0,0,0,0,offsetof(tnsMFace, mat),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY)->ElementBytes=2;
         laAddFloatProperty(p, "n", "Normal", "Normal", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsMFace, n),0,0,3,0,0,0,0,0,0,0,0);
         //laAddFloatProperty(p, "gn", "Global Normal", "Global normal", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsMFace, gn),0,0,3,0,0,0,0,0,0,0,0);
         laAddFloatProperty(p, "c", "Center", "Center", 0,"X,Y,Z", 0,0,0,0,0,0,offsetof(tnsMFace, c),0,0,3,0,0,0,0,0,0,0,0);
@@ -1265,6 +1289,18 @@ void la_RegisterTNSProps(){
     p = laAddPropertyContainer("tns_loop", "MFace Loop", "MFace Loop", 0,0,sizeof(laListItemPointer), 0,0,0);{
         laAddSubGroup(p, "e", "Edge", "Edge", "tns_medge",0,0,0,offsetof(laListItemPointer, p),0,0,0,0,0,0,0,LA_UDF_REFER);
     }
+
+    p = laAddPropertyContainer("tns_shape", "Shape", "Shape data structure", 0,0,sizeof(tnsShape), 0,0,0);{
+        laAddIntProperty(p,"mat","Material","Material of this face",0,0,0,0,0,0,0,0,offsetof(tnsShape, mat),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY)->ElementBytes=2;
+        laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsShape, flags),0,0,0,0,0,0,0,0,0,0,0);
+        laAddSubGroup(p, "points", "Points", "Points in this shape", "tns_spoint",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsShape, Points),0);
+    }
+    p = laAddPropertyContainer("tns_spoint", "SPoint", "Shape point", 0,0,sizeof(tnsSPoint), 0,0,0);{
+        laAddFloatProperty(p, "p", "Position", "Position", 0,"X,Y", 0,0,0,0,0,0,offsetof(tnsSPoint, p),0,0,2,0,0,0,0,0,0,0,0);
+        laAddFloatProperty(p, "dl", "Delta Left", "Delta of left control point", 0,"X,Y", 0,0,0,0,0,0,offsetof(tnsSPoint, dl),0,0,2,0,0,0,0,0,0,0,0);
+        laAddFloatProperty(p, "dr", "Delta Right", "Delta of right control point", 0,"X,Y", 0,0,0,0,0,0,offsetof(tnsSPoint, dr),0,0,2,0,0,0,0,0,0,0,0);
+        laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsSPoint, flags),0,0,0,0,0,0,0,0,0,0,0);
+        }
 }
 
 void la_RegisterInternalProps(){

+ 6 - 2
resources/la_widgets_viewers.c

@@ -146,8 +146,10 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
     glClearBufferfv(GL_COLOR, 2, gpos_clear);
 
     tnsRootObject* ro=root;
-    if(ro && ro->Is2D){ la_SetCanvasOrtho(ui); }
-    else{ tnsApplyCameraView(W, H, c); }
+    NVGcontext* vg=MAIN.CurrentWindow->nvg;
+    if(ro && ro->Is2D){ la_SetCanvasOrtho(ui);
+        nvgBeginFrame(vg,W,H,1); nvgTranslate(vg,-e->PanX/e->ZoomX+W/2,e->PanY/e->ZoomY+H/2);nvgScale(vg,1.0f/e->ZoomX,1.0f/e->ZoomY); 
+    }else{ tnsApplyCameraView(W, H, c); }
 
     tnsPushMatrix(); tnsPopMatrix(); //those are necessary when ui is the first in list;
 
@@ -207,6 +209,8 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
 
     glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND);
 
+    if(ro && ro->Is2D){ nvgEndFrame(MAIN.CurrentWindow->nvg); tnsRestoreFromNanoVG(); }
+
     //tnsDrawToOffscreen(e->OffScr, 1,0);
     //tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL)); tnsClearAll();
     //la_RootObjectDrawFullscreenQuad(e->DeferredOffScr, c, (real)W/(real)H);