*/}}
Jelajahi Sumber

Shape object draw and scale stuff seems ok

YimingWu 1 tahun lalu
induk
melakukan
52bff8f173
8 mengubah file dengan 184 tambahan dan 59 penghapusan
  1. 6 0
      la_interface.h
  2. 8 4
      la_tns.h
  3. 12 1
      la_tns_kernel.c
  4. 34 11
      la_tns_shape.c
  5. 45 27
      resources/la_modelling.c
  6. 9 2
      resources/la_properties.c
  7. 42 0
      resources/la_templates.c
  8. 28 14
      resources/la_widgets_viewers.c

+ 6 - 0
la_interface.h

@@ -892,6 +892,8 @@ NEED_STRUCTURE(laCanvasExtra);
 STRUCTURE(la3DObjectDrawExtra){
     int DisplayMode;
     int MeshEditType;
+    tnsMatrix44d mViewProj;
+    int W,H,Is3D;
 };
 
 typedef void(*laCanvasDrawFunc)(laBoxedTheme* bt, void* DataInstance, laCanvasExtra* Extra);
@@ -1876,6 +1878,7 @@ void laui_NodeCategory(laUiList *uil, laPropPack *This, laPropPack *Extra, laCol
 void tnsui_CameraObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
 void tnsui_LightObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
 void tnsui_MeshObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
+void tnsui_ShapeObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
 void tnsui_InstancerObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
 void tnsui_BaseObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
 void tnsui_RootObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
@@ -1901,6 +1904,9 @@ laUiList *la_FindSubListWithInstance(laUiItem *ui, void *Instance);
 void* laget_CurrentRackPage(laRackPageCollection* c);
 void laset_CurrentRackPage(laRackPageCollection* c,laRackPage* rp);
 
+void la_BeginNVG(struct NVGcontext* vg,laCanvasExtra* e,int W,int H, int Is2D);
+void la_SetCanvasOrtho(laCanvasExtra* e,int W, int H);
+
 #define LA_FILETYPE_UNKNOWN 0
 #define LA_FILETYPE_UDF 1
 #define LA_FILETYPE_DOCUMENT 2

+ 8 - 4
la_tns.h

@@ -452,10 +452,12 @@ typedef struct _tnsObject tnsObject;
 
 NEED_STRUCTURE(tnsBatch)
 
-#define TNS_EVAL_LAYER_SOLID (1<<0)
-#define TNS_EVAL_LAYER_OVERLAY (1<<1)
-#define TNS_EVAL_LAYER_OUTLINE (1<<2)
+#define TNS_EVAL_LAYER_SOLID     (1<<0)
+#define TNS_EVAL_LAYER_OVERLAY   (1<<1)
+#define TNS_EVAL_LAYER_OUTLINE   (1<<2)
 #define TNS_EVAL_LAYER_SELECTION (1<<3)
+#define TNS_EVAL_LAYER_NO_2D     (1<<4)
+#define TNS_EVAL_LAYER_BACKDROP  (1<<5)
 
 #define TNS_EVAL_MODE_INIT   (1<<0)
 #define TNS_EVAL_MODE_ALWAYS (1<<1)
@@ -494,6 +496,7 @@ STRUCTURE(tnsEvaluateData){
     int FillSelectionID;
     int OverrideID;
     laListHandle ParentStack;
+    tnsEvaluatedInstance* Backdrop; int NextBackdrop, MaxBackdrop;
     tnsEvaluatedInstance* Commands; int NextCommand, MaxCommand;
     tnsEvaluatedInstance* Outlines; int NextOutline, MaxOutline;
     tnsEvaluatedInstance* Overlays; int NextOverlay, MaxOverlay;
@@ -750,6 +753,7 @@ STRUCTURE(tnsShapeObject){
     laListHandle Materials;
 
     int Mode;
+    int Backdrop;
 };
 
 STRUCTURE(tnsMeshObject){
@@ -1180,7 +1184,7 @@ void la_RegisterModellingOperators();
 
 void tnsGetCameraProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera);
 void tnsGetCameraViewProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera);
-void tnsApplyCameraView(int W, int H, tnsCamera *Camera);
+void tnsApplyCameraView(int W, int H, tnsCamera *Camera, tnsMatrix44d out_optional_view, tnsMatrix44d out_optional_projection);
 void tnsApplyShadowCameraView(tnsLight *Light);
 
 void tnsApplyModelMatrix(tnsMatrix44d m);

+ 12 - 1
la_tns_kernel.c

@@ -3632,7 +3632,7 @@ void tnsGetCameraViewProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Came
     tnsMultiply44d(result, mat, inv);
     memcpy(mat, result, sizeof(tnsMatrix44d));
 }
-void tnsApplyCameraView(int W, int H, tnsCamera *Camera){
+void tnsApplyCameraView(int W, int H, tnsCamera *Camera, tnsMatrix44d out_optional_view, tnsMatrix44d out_optional_projection){
     tnsMatrixStackItem *tmsi = tKnlGetCurrentMatStackItem();
     tnsShader *current_shader = 0;
     real *mat;
@@ -3645,6 +3645,7 @@ void tnsApplyCameraView(int W, int H, tnsCamera *Camera){
     if (current_shader = T->CurrentShader){
         tnsShaderApplyProjection(current_shader, mat);
         tnsShaderApplyProjectionInverse(current_shader, mat);
+        if(out_optional_projection){ tnsCopyMatrix44d(mat,out_optional_projection); }
     }
 
     tnsResetViewMatrix();
@@ -3655,6 +3656,7 @@ void tnsApplyCameraView(int W, int H, tnsCamera *Camera){
 
     if (current_shader = T->CurrentShader){
         tnsShaderApplyView(current_shader, result);
+        if(out_optional_view){ tnsCopyMatrix44d(mat,out_optional_view); }
         if(current_shader->uViewPos>-1) glUniform3f(current_shader->uViewPos,LA_COLOR3(Camera->Base.GLocation));
         tnsVectorSet3v(T->SetViewPos,Camera->Base.GLocation);
     }
@@ -3937,6 +3939,9 @@ void tnsAddEvaluatedInstance(tnsEvaluateData* ed, tnsObject* ob, tnsDrawEvaluate
     if(Layer==TNS_EVAL_LAYER_SOLID){
         arrEnsureLength(&ed->Commands,ed->NextCommand,&ed->MaxCommand,sizeof(tnsEvaluatedInstance));
         ei=&ed->Commands[ed->NextCommand]; ed->NextCommand++;
+    }elif(Layer==TNS_EVAL_LAYER_BACKDROP){
+        arrEnsureLength(&ed->Backdrop,ed->NextBackdrop,&ed->MaxBackdrop,sizeof(tnsEvaluatedInstance));
+        ei=&ed->Backdrop[ed->NextBackdrop]; ed->NextBackdrop++;
     }elif(Layer==TNS_EVAL_LAYER_OUTLINE){
         arrEnsureLength(&ed->Outlines,ed->NextOutline,&ed->MaxOutline,sizeof(tnsEvaluatedInstance));
         ei=&ed->Outlines[ed->NextOutline]; ed->NextOutline++;
@@ -3954,6 +3959,7 @@ void tnsAddEvaluatedInstance(tnsEvaluateData* ed, tnsObject* ob, tnsDrawEvaluate
 }
 void tnsFreeEvaluatedArray(tnsEvaluateData* ed){
     ed->Done=0;
+    arrFree(&ed->Backdrop,&ed->MaxBackdrop);
     arrFree(&ed->Commands,&ed->MaxCommand);
     arrFree(&ed->Outlines,&ed->MaxOutline);
     arrFree(&ed->Overlays,&ed->MaxOverlay);
@@ -4041,6 +4047,7 @@ void tnsEvaluateObjectTree(tnsObject* from, tnsEvaluateData* UseED, int Evaluate
     ed->SceneEvaluateMode=EvaluatePlay;
     if(ed->Done) return;
     elif(!UseED){ ed->NextCommand=ed->NextOverlay=ed->NextSelection=ed->NextOutline=ed->NextMat=0;
+        if(!ed->Backdrop) arrInitLength(&ed->Backdrop,16,&ed->MaxBackdrop,sizeof(tnsEvaluatedInstance));
         if(!ed->Commands) arrInitLength(&ed->Commands,16,&ed->MaxCommand,sizeof(tnsEvaluatedInstance));
         if(!ed->Outlines) arrInitLength(&ed->Outlines,16,&ed->MaxOutline,sizeof(tnsEvaluatedInstance));
         if(!ed->Overlays) arrInitLength(&ed->Overlays,16,&ed->MaxOverlay,sizeof(tnsEvaluatedInstance));
@@ -4073,12 +4080,15 @@ void tnsEvaluateObjectTree(tnsObject* from, tnsEvaluateData* UseED, int Evaluate
 }
 void tnsDrawLayer(tnsEvaluateData* ed,int Layer,void* CustomData){
     tnsEvaluatedInstance* ei; int next=0;
+    int No2D=Layer&TNS_EVAL_LAYER_NO_2D; Layer&=(~TNS_EVAL_LAYER_NO_2D);
     if(Layer==TNS_EVAL_LAYER_SOLID){ ei=ed->Commands; next=ed->NextCommand; }
+    elif(Layer==TNS_EVAL_LAYER_BACKDROP){ ei=ed->Backdrop; next=ed->NextBackdrop; }
     elif(Layer==TNS_EVAL_LAYER_OUTLINE){ ei=ed->Outlines; next=ed->NextOutline; }
     elif(Layer==TNS_EVAL_LAYER_OVERLAY){ ei=ed->Overlays; next=ed->NextOverlay; }
     elif(Layer==TNS_EVAL_LAYER_SELECTION){ ei=ed->Selections; next=ed->NextSelection; }
     else{ return; } if(!next){ return; }
     for(int i=0;i<next;i++){
+        if(No2D && ei->Object->Type==TNS_OBJECT_SHAPE){ ei++; continue; }
         tnsPushMatrix(); tnsApplyModelMatrix(ei->Mat);
         ei->Draw(ei,CustomData);
         tnsPopMatrix();
@@ -4089,6 +4099,7 @@ void tnsDrawObjectTree(tnsObject* from, int Layers,void* CustomData, int DrawRun
     if(!from) return;
     tnsEvaluateData* ed=DrawRuntime?&from->EvaluatedPlay:&from->Evaluated;
     if(!ed->Done) return;
+    if(Layers&TNS_EVAL_LAYER_BACKDROP){ tnsDrawLayer(ed,TNS_EVAL_LAYER_BACKDROP,CustomData); }
     if(Layers&TNS_EVAL_LAYER_SOLID){ tnsDrawLayer(ed,TNS_EVAL_LAYER_SOLID,CustomData); }
     if(Layers&TNS_EVAL_LAYER_OUTLINE){ tnsDrawLayer(ed,TNS_EVAL_LAYER_OUTLINE,CustomData);}
     if(Layers&TNS_EVAL_LAYER_OVERLAY){ tnsDrawLayer(ed,TNS_EVAL_LAYER_OVERLAY,CustomData);}

+ 34 - 11
la_tns_shape.c

@@ -47,28 +47,51 @@ void tns_DrawShape(tnsShape* s, real* override_color){
     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));
+	nvgFillColor(vg, override_color?nvgRGBAf(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 tnsDrawShapeObjectShapes(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de, real* override_color){
+    tnsShapeObject* so=ei->Object; NVGcontext* vg=MAIN.CurrentWindow->nvg;
+    real sca[3]; tnsExtractScale44d(ei->Mat,sca);
+    real rot[3]; tnsExtractXYZEuler44d(ei->Mat,rot);
+    nvgSave(vg);
+    if(de->Is3D){
+        tnsVector4d pos; tnsApplyTransform44d(pos,de->mViewProj,&ei->Mat[12]);
+        pos[0]/=pos[3]; pos[1]/=pos[3];
+        nvgTranslate(vg,pos[0]*de->W/2,pos[1]*de->H/2);
+        nvgScale(vg,LA_RH*sca[0],LA_RH*sca[1]); nvgRotate(vg,rot[2]);
+    }else{
+        nvgTranslate(vg,ei->Mat[12],-ei->Mat[13]);
+        nvgScale(vg,sca[0],-sca[1]); nvgRotate(vg,rot[2]);
     }
+    for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ tns_DrawShape(s,override_color); }
+    nvgRestore(vg);
 }
-void tnsDrawShapeObjectSelectionID(tnsEvaluatedInstance* ei, void* unused){
-    tnsShapeObject* so=ei->Object;
+void tnsDrawShapeObject(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
+    tnsDrawShapeObjectShapes(ei,de,0);
+}
+void tnsDrawShapeObjectSelectionID(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
     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);
-    }
+    tnsDrawShapeObjectShapes(ei,de,color);
+}
+void tnsDrawShapeObjectOverlay(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
+    int i=ei->InstanceSelectionID; real color[4]; tnsVectorCopy4d(laAccentColor(LA_BT_ACTIVE),color);
+    if(ei->Object!=ei->Object->InRoot->Active){ color[3]=0.4; }else{ color[3]=0.7; }
+    tnsDrawShapeObjectShapes(ei,de,color);
 }
 
 void tnsEvaluateShapeObject(tnsShapeObject* so, tnsEvaluateData* ed){
-    tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObject,TNS_EVAL_LAYER_SOLID,0,0,0);
+    int DrawTo=TNS_EVAL_LAYER_SOLID;
+    if(so->Backdrop){ DrawTo=TNS_EVAL_LAYER_BACKDROP; }
+    tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObject,DrawTo,0,0,0);
     if(ed->FillSelectionID){
         tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,so->Base.SelectID);
     }
+    if(ed->FillOutline && (!ed->OverrideID)){
+        if((so->Base.Flags&TNS_OBJECT_FLAGS_SELECTED) && (so->Mode!=TNS_MESH_EDIT_MODE)){
+            tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectOverlay,TNS_EVAL_LAYER_OVERLAY,0,0,0);
+        }
+    }
 }
 
 tnsShapeObject *tnsCreateShapeEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){

+ 45 - 27
resources/la_modelling.c

@@ -17,6 +17,7 @@
 */
 
 #include "../la_5.h"
+#include "nanovg.h"
 
 extern LA MAIN;
 extern struct _tnsMain *T;
@@ -106,7 +107,8 @@ void la_AssignObjectSelectIDRecursive(tnsObject* root, MSelectData* sd){
         if(o->ChildObjects.pFirst){ la_AssignObjectSelectIDRecursive(o,sd); }
     }
 }
-void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* camera){
+void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, laCanvasExtra* e){
+    tnsCamera* camera=e->ViewingCamera;
     arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsObject*));
     sd->nextV++; // starting from 1;
     la_AssignObjectSelectIDRecursive(root, sd);
@@ -115,13 +117,20 @@ void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* c
     tnsEnableShaderv(T->SelectionShader);
     glDisableVertexAttribArray(T->SelectionShader->iColor); glVertexAttrib4f(T->SelectionShader->iColor,0,0,0,0);
     tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
-    tnsApplyCameraView(w,h,camera);
-    glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-    glEnable(GL_DEPTH_TEST);
+    
+    NVGcontext* vg=MAIN.CurrentWindow->nvg;
+    la3DObjectDrawExtra de={0}; de.W=w; de.H=h;
+    tnsMatrix44d mview,mproj; tnsRootObject* ro=root;
+    if(ro && ro->Is2D){ la_SetCanvasOrtho(e,w,h); }
+    else{ tnsApplyCameraView(w, h, camera, mview,mproj); tnsMultiply44d(de.mViewProj,mproj,mview); de.Is3D=1; }
+    la_BeginNVG(vg,e,w,h,ro->Is2D);
+
+    glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST);
     tnsInvalidateEvaluation(root); tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1); tnsEvaluateObjectTree(root,0,0);
-    tnsDrawObjectTree(root,TNS_EVAL_LAYER_SELECTION,0,0);
-    glDisable(GL_DEPTH_TEST);
-    tnsEnableShaderv(T->immShader);
+    tnsDrawObjectTree(root,TNS_EVAL_LAYER_SELECTION,&de,0);
+    glDisable(GL_DEPTH_TEST); 
+
+    nvgEndFrame(vg); tnsRestoreFromNanoVG(); tnsEnableShaderv(T->immShader);
 }
 void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
     arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsMVert*));
@@ -150,7 +159,7 @@ void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCame
     tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
     tnsEnableShaderv(T->SelectionShader);
     tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
-    tnsApplyCameraView(w,h,camera);
+    tnsApplyCameraView(w,h,camera,0,0);
     glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
     tnsPushMatrix(); tnsApplyModelMatrix(mo->Base.GlobalTransform);glEnable(GL_DEPTH_TEST);
     if(!SelectThrough){
@@ -337,7 +346,7 @@ int OPINV_Select(laOperator *a, laEvent *e){
         tnsInvalidateMeshBatch(mo);
         laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Mesh selection",TNS_HINT_GEOMETRY);
     }else{
-        la_PopulateSelectDataObjects(sd,root,ex->ViewingCamera);
+        la_PopulateSelectDataObjects(sd,root,ex);
         if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
             MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
             ex->OnX=e->x; ex->OnX=e->y;
@@ -435,9 +444,10 @@ STRUCTURE(MTransformData){
     real DeltaVal, UserDeltaVal;
     laStringEdit* Entry; int UseUserDelta;
     int CanvasDeltaMode;
+    int Is2D; real zoomx,zoomy;
 };
 
-MTransformData* la_InitTransformData(int w, int h, tnsCamera* c, int CanvasDeltaMode){
+MTransformData* la_InitTransformData(int w, int h, tnsCamera* c, int CanvasDeltaMode, int Is2D,real zoomx,real zoomy){
     MTransformData* td=memAcquireSimple(sizeof(MTransformData));
     tnsVector4d pu={0,1,0,0}, pr={1,0,0,0}, pf={0,0,1};
     tnsGetCameraMovingDeltas(c,w,h,1,0,pr); pr[2]=0; pr[3]=0;
@@ -446,10 +456,10 @@ MTransformData* la_InitTransformData(int w, int h, tnsCamera* c, int CanvasDelta
     tnsApplyRotation43d(td->Up,inv,pu);
     tnsApplyRotation43d(td->Right,inv,pr);
     tnsApplyRotation43d(td->Foward,inv,pf);
-
     tnsGetCameraViewProjection(td->ViewProjection, w,h,c);
     td->c=c; td->w=w; td->h=h; td->CanvasDeltaMode=CanvasDeltaMode;
     strBeginEdit(&td->Entry, "");
+    td->Is2D=Is2D; td->zoomx=zoomx; td->zoomy=zoomy;
     return td;
 }
 void la_GetTransformInitialScale(MTransformData* td, laUiItem* ui, int x, int y){ td->Initial=tnsDistIdv2(x-ui->L,y-ui->U,td->CenterX,td->CenterY); }
@@ -502,16 +512,21 @@ int la_PopulateTransformVerticies(MTransformData* td, tnsMeshObject* mo){
     return any;
 }
 void la_ApplyTranslation(MTransformData* td, int x, int y){
-    tnsMatrix44d trans; tnsVector3d deltay,delta; tnsVector3d gp;
-    tnsVectorMulti3d(delta, td->Right, x); tnsVectorMulti3d(deltay, td->Up, y); tnsVectorAccum3d(delta, deltay);
-    tnsVector3d use_delta={LA_COLOR3(delta)}; real len;
-    if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ len=tnsLength3d(delta); }
-    if(td->LockAxis[0]>0){ use_delta[1]=use_delta[2]=0; real l=fabs(use_delta[0]); use_delta[0]=l?use_delta[0]*len/l:1e-7; }
-    if(td->LockAxis[1]>0){ use_delta[0]=use_delta[2]=0; real l=fabs(use_delta[1]); use_delta[1]=l?use_delta[1]*len/l:1e-7; }
-    if(td->LockAxis[2]>0){ use_delta[0]=use_delta[1]=0; real l=fabs(use_delta[2]); use_delta[2]=l?use_delta[2]*len/l:1e-7; }
-    if(td->LockAxis[0]<0){ use_delta[0]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
-    if(td->LockAxis[1]<0){ use_delta[1]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
-    if(td->LockAxis[2]<0){ use_delta[2]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
+    tnsMatrix44d trans; tnsVector3d deltay,delta; tnsVector3d gp; tnsVector3d use_delta;
+    if(td->Is2D){
+        use_delta[0]=x*td->zoomx; use_delta[1]=-y*td->zoomy; use_delta[2]=0;
+        if(td->LockAxis[0]){ use_delta[1]=0; } if(td->LockAxis[1]){ use_delta[0]=0; }
+    }else{
+        tnsVectorMulti3d(delta, td->Right, x); tnsVectorMulti3d(deltay, td->Up, y); tnsVectorAccum3d(delta, deltay);
+        tnsVectorSet3v(use_delta,delta); real len;
+        if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ len=tnsLength3d(delta); }
+        if(td->LockAxis[0]>0){ use_delta[1]=use_delta[2]=0; real l=fabs(use_delta[0]); use_delta[0]=l?use_delta[0]*len/l:1e-7; }
+        if(td->LockAxis[1]>0){ use_delta[0]=use_delta[2]=0; real l=fabs(use_delta[1]); use_delta[1]=l?use_delta[1]*len/l:1e-7; }
+        if(td->LockAxis[2]>0){ use_delta[0]=use_delta[1]=0; real l=fabs(use_delta[2]); use_delta[2]=l?use_delta[2]*len/l:1e-7; }
+        if(td->LockAxis[0]<0){ use_delta[0]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
+        if(td->LockAxis[1]<0){ use_delta[1]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
+        if(td->LockAxis[2]<0){ use_delta[2]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
+    }
     td->DeltaVal=tnsLength3d(use_delta);
     if(td->UseUserDelta){
         tnsVectorMultiSelf3d(use_delta,1/tnsLength3d(use_delta)*td->UserDeltaVal);
@@ -576,11 +591,12 @@ void la_ApplyScale(MTransformData* td, int uix, int uiy){
 void la_ApplyRotation(MTransformData* td, int uix, int uiy){
     tnsMatrix44d trans; real a=atan2(uiy-td->CenterY,uix-td->CenterX);
     real angle=a-td->Initial; tnsVector3d gp; tnsVector3d LimFoward={0}; real* use_forward=td->Foward;
+    if(td->Is2D){ use_forward=LimFoward; LimFoward[2]=1; }
     if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ use_forward=LimFoward; }
-    if(td->LockAxis[0]){ LimFoward[0]=1; }
-    if(td->LockAxis[1]){ LimFoward[1]=1; }
+    if(td->LockAxis[0]){ LimFoward[0]=1; LimFoward[2]=0; }
+    if(td->LockAxis[1]){ LimFoward[1]=1; LimFoward[2]=0; }
     if(td->LockAxis[2]){ LimFoward[2]=1; }
-     if(td->UseUserDelta) angle=rad(td->UserDeltaVal); td->DeltaVal=deg(angle);
+    if(td->UseUserDelta) angle=rad(td->UserDeltaVal); td->DeltaVal=deg(angle);
     if(!td->mo){
         for(int i=0;i<td->next;i++){
             MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
@@ -667,9 +683,11 @@ int la_InitTransform(laOperator* a, laEvent* e, int mode, int restore_type, int
     if(!a->This || !a->This->EndInstance){ return 0; }
     laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
     tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
-    tnsMeshObject* mo=root->Active;
+    tnsMeshObject* mo=root->Active; tnsRootObject*ro=root;
 
-    MTransformData* td=la_InitTransformData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c, ex->DeltaMode);
+    MTransformData* td=la_InitTransformData(
+        ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c, ex->DeltaMode,
+        ro->Is2D, ex->ZoomX,ex->ZoomY);
     a->CustomData = td;
     td->mode=mode;
     td->root=root;
@@ -1255,7 +1273,7 @@ int OPINV_Add(laOperator *a, laEvent *e){
         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; }
+            no=tnsCreateShapeSquare(root, "Square",0,0,0,1); 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"); }
     }elif(mo->Base.Type==TNS_OBJECT_MESH && mo->Mode!=TNS_MESH_EDIT_MODE){ ad->Context=LA_ADD_CTX_MESH;

+ 9 - 2
resources/la_properties.c

@@ -914,6 +914,9 @@ 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);
 }
+void tnsset_ShapeObjectBackdrop(tnsShapeObject* o, int v){
+    o->Backdrop=v; tnsInvalidateEvaluation(o); laNotifyUsers("tns.world");
+}
 tnsMaterial* tnsget_FirstMaterial(void* unused1, void* unused2){
     return T->World->Materials.pFirst;
 }
@@ -1241,15 +1244,19 @@ 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);{
+    p = laAddPropertyContainer("tns_shape_object", "Shape Object", "Shape object", 0,tnsui_ShapeObjectProperties,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);{
+        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);
         }
+        ep = laAddEnumProperty(p, "backdrop", "Backdrop", "Draw shape as backdrop", 0,0,0,0,0,offsetof(tnsShapeObject, Backdrop),0,tnsset_ShapeObjectBackdrop,0,0,0,0,0,0,0,0);{
+            laAddEnumItemAs(ep, "NONE", "None", "Draw shape on top of stuff", 0, 0);
+            laAddEnumItemAs(ep, "BACKDROP", "Backdrop", "Draw shape as backdrop", 1, 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);

+ 42 - 0
resources/la_templates.c

@@ -1872,6 +1872,48 @@ void tnsui_MeshObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNU
         laShowLabel(gu,gc,"No active material slot.",0,0);
     }laEndCondition(gu,b2);
 }
+void tnsui_ShapeObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil); laUiItem* g,*tg; laUiList* gu,*tu; laColumn* gc,*gcl,*gcr,*tc; laUiItem* b1,*b2,*b3,*b4,*b5;
+    laShowLabel(uil,c,"Shape Object",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED; 
+    g=laMakeGroup(uil,c,"Materials",0); gu=g->Page; gc=laFirstColumn(gu); laSplitColumn(gu,gc,0.4);
+    gcl=laLeftColumn(gc,10); gcr=laRightColumn(gc,0);
+    laShowLabel(gu,gcl,"Backdrop",0,0);
+    laShowItemFull(gu,gcr,This,"backdrop",0,"text=Backdrop",0,0)->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
+
+    g=laMakeGroup(uil,c,"Materials",0); gu=g->Page; gc=laFirstColumn(gu); laSplitColumn(gu,gc,0.7);
+    gcl=laLeftColumn(gc,0); gcr=laRightColumn(gc,1);
+    tg=laMakeEmptyGroup(gu,gcl,"Slots",0); tu=tg->Page; tc=laFirstColumn(tu); tu->HeightCoeff=4;
+    laShowItemFull(tu,tc,This,"materials",0,0,tnsui_MaterialSlot,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+    laShowItem(gu,gcr,This,"add_material_slot");
+    b2=laOnConditionThat(gu,gc,laPropExpression(This,"current_material"));{
+        laUiItem* mat=laShowInvisibleItem(gu,gc,This,"current_material");
+        laShowItem(gu,gcr,&mat->PP,"remove");
+        b3=laBeginRow(gu,gc,0,0); laUiItem* sel;
+        laShowItem(gu,gc,This,"add_material")->Flags|=LA_UI_FLAGS_ICON;
+        b4=laOnConditionThat(gu,gc,laPropExpression(&mat->PP,"material"));{
+            sel=laShowItemFull(gu,gc,&mat->PP,"material",LA_WIDGET_COLLECTION_SELECTOR,0,tnsui_MaterialListItem,0);
+            sel->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
+            laShowItem(gu,gc,&mat->PP,"material.name")->Expand=1;
+            laShowItem(gu,gc,&sel->PP,"clear_selection")->Flags|=LA_UI_FLAGS_ICON;
+        }laElse(gu,b4);{
+            sel=laShowItemFull(gu,gc,&mat->PP,"material",LA_WIDGET_COLLECTION_SELECTOR,0,tnsui_MaterialListItem,0);
+            sel->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR; sel->Expand=1;
+        }laEndCondition(gu,b4);
+        laEndRow(gu,b3);
+        b4=laOnConditionThat(gu,gc,laEqual(laPropExpression(This,"mode"),laIntExpression(TNS_MESH_EDIT_MODE)));{
+            b5=laBeginRow(gu,gc,0,0);
+            laShowLabel(gu,gc,"Edit:",0,0);
+            laShowItemFull(gu,gc,This,"assign_material_slot",0,"text=Assign",0,0);
+            laEndRow(gu,b5);
+        }laEndCondition(gu,b4);
+        laShowSeparator(gu,gc);
+        b4=laOnConditionThat(gu,gc,laPropExpression(&mat->PP,"material"));{
+            laShowItemFull(gu,gc,&mat->PP,"material",LA_WIDGET_COLLECTION_SINGLE,0,tnsui_Material,1)->Flags|=LA_UI_FLAGS_NO_DECAL;
+        }laEndCondition(gu,b4);
+    }laElse(gu,b2);{
+        laShowLabel(gu,gc,"No active material slot.",0,0);
+    }laEndCondition(gu,b2);
+}
 void tnsui_InstancerObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
     laColumn* c=laFirstColumn(uil), *cl,*cr;
     laSplitColumn(uil,c,0.5); cl=laLeftColumn(c,5); cr=laRightColumn(c,0);

+ 28 - 14
resources/la_widgets_viewers.c

@@ -25,11 +25,20 @@ extern struct _tnsMain *T;
 
 extern tnsFontManager *FM;
 
-void la_SetCanvasOrtho(laUiItem* ui){
-    laCanvasExtra* e=ui->Extra; int W, H; W = ui->R - ui->L; H = ui->B - ui->U;
+void la_SetCanvasOrtho(laCanvasExtra* e,int W, int H){
     real x2=(real)W*e->ZoomX/2,y2=(real)H*e->ZoomY/2;
     tnsOrtho(e->PanX-x2,e->PanX+x2,e->PanY-y2,e->PanY+y2,100,-100);
 }
+void la_BeginNVG(NVGcontext* vg,laCanvasExtra* e,int W,int H, int Is2D){
+    nvgBeginFrame(vg,W,H,1);
+    if(Is2D){
+        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{
+        nvgTranslate(vg,W/2,H/2);
+        nvgScale(vg,1,-1);
+    }
+}
 
 void la_RootObjectDrawFullscreenQuad(tnsOffscreen* DeferredOffScr,tnsCamera* c, real Aspect){
     real FOV = c->FOV;
@@ -109,7 +118,7 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
         //tnsUseSceneShader();
         //tnsEnableShaderv(T->SceneShader);
         //tnsApplyShadowCameraView(e->CurrentScene->ActiveSun);
-        tnsApplyCameraView(W, H, c);
+        tnsApplyCameraView(W, H, c,0,0);
 //
         //tnsUseTexture(e->OffScrShadow->pDepth);
 //
@@ -145,25 +154,29 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
     tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL)); tnsClearAll(); float gpos_clear[]={-1e20, -1e20, -1e20, 0};
     glClearBufferfv(GL_COLOR, 2, gpos_clear);
 
+    la3DObjectDrawExtra de={0};
+    de.MeshEditType=e->SelectMode; de.DisplayMode=e->AsPlayer?LA_CANVAS_DISPLAY_MATERIAL:e->DisplayMode;
+    de.W=W; de.H=H;
+
     tnsRootObject* ro=root;
     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); }
+    tnsMatrix44d mview,mproj;
+    if(ro && ro->Is2D){ la_SetCanvasOrtho(e,W,H); }
+    else{ tnsApplyCameraView(W, H, c, mview,mproj); tnsMultiply44d(de.mViewProj,mproj,mview); de.Is3D=1; }
 
     tnsPushMatrix(); tnsPopMatrix(); //those are necessary when ui is the first in list;
 
-    laListHandle xrays={0};
-
-    la3DObjectDrawExtra de={0};
-    de.MeshEditType=e->SelectMode; de.DisplayMode=e->AsPlayer?LA_CANVAS_DISPLAY_MATERIAL:e->DisplayMode;
-
     if(root){
         if(!e->AsPlayer){
             tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1);
             tnsEvaluateObjectTree(root,0,0);
         }
 
+        la_BeginNVG(vg,e,W,H,ro->Is2D);
+        tnsDrawObjectTree(root,TNS_EVAL_LAYER_BACKDROP,&de,e->AsPlayer);
+        nvgEndFrame(vg); tnsRestoreFromNanoVG();
+        la_BeginNVG(vg,e,W,H,ro->Is2D);
+
         glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND);
 
         tnsUseShader(T->immShader); tnsEnableShaderv(T->immShader); tnsUseNoTexture();
@@ -209,7 +222,7 @@ 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(); }
+    nvgEndFrame(vg); tnsRestoreFromNanoVG();
 
     //tnsDrawToOffscreen(e->OffScr, 1,0);
     //tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL)); tnsClearAll();
@@ -293,7 +306,7 @@ void la_CanvasDrawTexture(laBoxedTheme *bt, tnsTexture *t, laUiItem* ui){
     tnsDrawToOffscreen(e->OffScr, 1, 0);
     tnsViewportWithScissor(0, 0, W, H);
     tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
-    la_SetCanvasOrtho(ui);
+    la_SetCanvasOrtho(e,W,H);
 
     //glClearColor(0.3,0.3,0.3, 1);
     if (e->ClearBackground){ tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL)); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }
@@ -610,6 +623,7 @@ void la_3DViewInit(laUiItem *ui){
     e->ShowAxis[0] = 1; e->ShowAxis[1] = 1;
     e->ShowFloorGrid = 1;
     e->HeightCoeff = 10;
+    e->ZoomX=1.0f/LA_RH; e->ZoomY=1.0f/LA_RH;
 
     laRecordDifferences(0,"tns.world");
     laPushDifferences("Created camera for 3D view widget,",0);
@@ -968,7 +982,7 @@ int OPMOD_3DViewCameraMove(laOperator *a, laEvent *e){
     laGeneralUiExtraData *uex = a->CustomData;
     laUiItem* ui=ex->ParentUi; tnsRootObject* root=ui->PP.EndInstance;
     if(root && root->Base.Type==TNS_OBJECT_ROOT && root->Is2D){
-        return LA_FINISHED;
+        return OPMOD_CanvasMove(a,e);
     }
 
     if (e->Type == LA_L_MOUSE_UP || e->Type == LA_M_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN){