|  | @@ -118,7 +118,7 @@ void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* c
 | 
	
		
			
				|  |  |      tnsApplyCameraView(w,h,camera);
 | 
	
		
			
				|  |  |      glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 | 
	
		
			
				|  |  |      glEnable(GL_DEPTH_TEST);
 | 
	
		
			
				|  |  | -    tnsDrawObjectTree(root,0,0,0);
 | 
	
		
			
				|  |  | +    tnsDrawObjectTree(root,0,0,0,0,0,0);
 | 
	
		
			
				|  |  |      glDisable(GL_DEPTH_TEST);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
 | 
	
	
		
			
				|  | @@ -139,7 +139,7 @@ void la_PopulateSelectEdges(MSelectData* sd, tnsMeshObject* mo){
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      sd->nextE++;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera, int WhatPrim){
 | 
	
		
			
				|  |  | +void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera, int WhatPrim, int SelectThrough){
 | 
	
		
			
				|  |  |      int DoVerts=(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS),DoEdges=(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES);
 | 
	
		
			
				|  |  |      int Knife=(WhatPrim==LA_CANVAS_SELECT_MODE_KNIFE);
 | 
	
		
			
				|  |  |      if(DoVerts || Knife){ la_PopulateSelectVerts(sd,mo); }
 | 
	
	
		
			
				|  | @@ -150,12 +150,17 @@ void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCame
 | 
	
		
			
				|  |  |      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);
 | 
	
		
			
				|  |  | -    tnsPushMatrix(); tnsApplyObjectMatrix(mo);
 | 
	
		
			
				|  |  | -    if(Knife){ glPointSize(5); }
 | 
	
		
			
				|  |  | +    tnsPushMatrix(); tnsApplyObjectMatrix(mo);glEnable(GL_DEPTH_TEST);
 | 
	
		
			
				|  |  | +    if(!SelectThrough){
 | 
	
		
			
				|  |  | +        glDepthMask(GL_TRUE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 | 
	
		
			
				|  |  | +        tnsUniformUseOffset(T->SelectionShader,0);
 | 
	
		
			
				|  |  | +        tnsDrawBatch(mo->Batch,"body",0,0);
 | 
	
		
			
				|  |  | +        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_FALSE);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    tnsUniformUseOffset(T->SelectionShader,1);
 | 
	
		
			
				|  |  |      if(DoEdges || Knife){ tnsDrawBatch(mo->Batch, "edges_select",0,0); }
 | 
	
		
			
				|  |  |      if(DoVerts || Knife){ tnsDrawBatch(mo->Batch, "verts_select",0,0); }
 | 
	
		
			
				|  |  | -    if(Knife){ glPointSize(1); }
 | 
	
		
			
				|  |  | +    tnsUniformUseOffset(T->SelectionShader,0);
 | 
	
		
			
				|  |  |      tnsPopMatrix();
 | 
	
		
			
				|  |  |      glDisable(GL_DEPTH_TEST);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -204,18 +209,23 @@ uint8_t* la_ReadSelectionBox(MSelectData* sd, int uix, int uiy, int uix2, int ui
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius, int *ElemType){
 | 
	
		
			
				|  |  |      *ElemType=0; uint8_t* buf=la_ReadSelectionRadius(sd, uix, uiy, radius); if(!buf) return 0;
 | 
	
		
			
				|  |  | -    int w=radius*2; int MinD=INT_MAX; int MinID=0, d, elemtype=0;
 | 
	
		
			
				|  |  | +    int w=radius*2; int MinD=INT_MAX,MinDe=INT_MAX; int MinID=0,MinIDe=0, d, elemtype=0;
 | 
	
		
			
				|  |  |      for(int i=0;i<w;i++){
 | 
	
		
			
				|  |  |          for(int j=0;j<w;j++){
 | 
	
		
			
				|  |  | -            uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|((p[2]<<16)&(~TNS_MMESH_TYPE_BIT));
 | 
	
		
			
				|  |  | -            if(id && (d=tnsDistIdv2(i,j, radius, radius))<MinD ){ MinD=d; MinID=id; elemtype=((p[2]<<16)&TNS_MMESH_TYPE_BIT); }
 | 
	
		
			
				|  |  | +            uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|((p[2]<<16)&(~TNS_MMESH_TYPE_BIT)); if(!id){continue;}
 | 
	
		
			
				|  |  | +            d=tnsDistIdv2(i,j, radius, radius); elemtype=((p[2]<<16)&TNS_MMESH_TYPE_BIT);
 | 
	
		
			
				|  |  | +            if(elemtype==TNS_MMESH_EDGE_BIT){ if(d<MinDe){ MinDe=d; MinIDe=id; } }
 | 
	
		
			
				|  |  | +            elif(d<MinD){ MinD=d; MinID=id; }
 | 
	
		
			
				|  |  |              //printf("%d ",buf[(i*w+j)*4]);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          //printf("\n");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    printf("%d %d\n",MinID, MinIDe);
 | 
	
		
			
				|  |  |      free(buf);
 | 
	
		
			
				|  |  | -    *ElemType=elemtype;
 | 
	
		
			
				|  |  | -    return MinID;
 | 
	
		
			
				|  |  | +    if(MinID && MinIDe){ if(MinD<MinDe*5){ *ElemType=0; return MinID; } }
 | 
	
		
			
				|  |  | +    if(MinIDe){ *ElemType=TNS_MMESH_EDGE_BIT; return MinIDe; }
 | 
	
		
			
				|  |  | +    if(MinID){ *ElemType=0; return MinID; }
 | 
	
		
			
				|  |  | +    *ElemType=0; return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  int* la_SelectGetBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2, int* r_length){
 | 
	
		
			
				|  |  |      uint8_t* buf=la_ReadSelectionBox(sd, uix, uiy, uix2, uiy2); if(!buf) return 0;
 | 
	
	
		
			
				|  | @@ -308,7 +318,7 @@ int OPINV_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      int Append=e->SpecialKeyBit&LA_KEY_SHIFT; if(Append) DeselectAll=0;
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | -        la_PopulateSelectDataPrimitives(sd, mo, ex->ViewingCamera, SelectMode);
 | 
	
		
			
				|  |  | +        la_PopulateSelectDataPrimitives(sd, mo, ex->ViewingCamera, SelectMode, ex->SelectThrough);
 | 
	
		
			
				|  |  |          if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
 | 
	
		
			
				|  |  |              MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
 | 
	
		
			
				|  |  |              ex->OnX=e->x; ex->OnX=e->y;
 | 
	
	
		
			
				|  | @@ -1306,21 +1316,21 @@ STRUCTURE(MKnifeElement){
 | 
	
		
			
				|  |  |      void* p;
 | 
	
		
			
				|  |  |      int Type;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  | -void la_KnifeUpdateToolBatch(MSelectExtra* se,tnsObject* o){
 | 
	
		
			
				|  |  | -    if(se->root->ExtraBatch) tnsDeleteBatch(se->root->ExtraBatch); se->root->ExtraBatch=0;
 | 
	
		
			
				|  |  | +void la_KnifeUpdateToolBatch(MSelectExtra* se,tnsMeshObject* o){
 | 
	
		
			
				|  |  | +    if(o->ExtraBatch) tnsDeleteBatch(o->ExtraBatch); o->ExtraBatch=0;
 | 
	
		
			
				|  |  |      int count=lstCountElements(&se->KnifeElements); if((!count) && (!se->PendingElem)) return;
 | 
	
		
			
				|  |  |      float* points=calloc((count+1)*3,sizeof(real));
 | 
	
		
			
				|  |  |      float* p=points; real tmp[3],trans[4];
 | 
	
		
			
				|  |  |      for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
 | 
	
		
			
				|  |  |          if(ke->Type==TNS_MMESH_EDGE_BIT){ tnsMEdge* me=ke->p; tnsVectorSet3v(tmp,me->vl->p); tnsVectorAccum3d(tmp,me->vr->p);
 | 
	
		
			
				|  |  | -            tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  | -        else{ tnsMVert* mv=ke->p; tnsApplyTransform43d(trans,o->GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  | +            tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->Base.GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  | +        else{ tnsMVert* mv=ke->p; tnsApplyTransform43d(trans,o->Base.GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  |          p+=3;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if(se->PendingElem){
 | 
	
		
			
				|  |  |          if(se->PendingElemType==TNS_MMESH_EDGE_BIT){ tnsMEdge* me=se->PendingElem; tnsVectorSet3v(tmp,me->vl->p); tnsVectorAccum3d(tmp,me->vr->p);
 | 
	
		
			
				|  |  | -        tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  | -        else{ tnsMVert* mv=se->PendingElem; tnsApplyTransform43d(trans,o->GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  | +        tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->Base.GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  | +        else{ tnsMVert* mv=se->PendingElem; tnsApplyTransform43d(trans,o->Base.GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
 | 
	
		
			
				|  |  |      }elif(count){
 | 
	
		
			
				|  |  |          tnsVectorSet3v(p,p-3);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1328,6 +1338,7 @@ void la_KnifeUpdateToolBatch(MSelectExtra* se,tnsObject* o){
 | 
	
		
			
				|  |  |      tnsBatch* batch=tnsCreateBatch(count+1,3,points,0,0,0,0); tnsBatchCommand*c;
 | 
	
		
			
				|  |  |      c=tnsCreateCommand(batch, "hovering_point", 1, 3, GL_POINTS, &elem, 0);
 | 
	
		
			
				|  |  |      tnsCommandUseUniformColor(c,laAccentColor(LA_BT_SVERTEX));
 | 
	
		
			
				|  |  | +    tnsCommandUseWidth(c, 8);
 | 
	
		
			
				|  |  |      if(count){
 | 
	
		
			
				|  |  |          c=tnsCreateCommand(batch, "edges", count+(se->IsLoop?0:1), 3, se->IsLoop?GL_LINE_LOOP:GL_LINE_STRIP, 0, 0);
 | 
	
		
			
				|  |  |          tnsCommandUseUniformColor(c,laAccentColor(LA_BT_NORMAL));
 | 
	
	
		
			
				|  | @@ -1336,7 +1347,7 @@ void la_KnifeUpdateToolBatch(MSelectExtra* se,tnsObject* o){
 | 
	
		
			
				|  |  |          tnsCommandUseUniformColor(c,laAccentColor(LA_BT_NORMAL));
 | 
	
		
			
				|  |  |          tnsCommandUseWidth(c, 6);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    se->root->ExtraBatch=batch;
 | 
	
		
			
				|  |  | +    o->ExtraBatch=batch;
 | 
	
		
			
				|  |  |      free(points);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  int la_KnifeIsDuplicated(MSelectExtra* se, void* ref){
 | 
	
	
		
			
				|  | @@ -1366,7 +1377,7 @@ int la_KnifeRegisterCuts(MSelectExtra* se, tnsMeshObject* mo, int TryClose){
 | 
	
		
			
				|  |  |      if(changed){ tnsMMeshRefreshIndex(mo); tnsMMeshCalculateNormal(mo); }
 | 
	
		
			
				|  |  |      return changed;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -void la_KnifeFinish(MSelectExtra* se, tnsObject*o){
 | 
	
		
			
				|  |  | +void la_KnifeFinish(MSelectExtra* se, tnsMeshObject*o){
 | 
	
		
			
				|  |  |      if(o->ExtraBatch) tnsDeleteBatch(o->ExtraBatch); o->ExtraBatch=0;
 | 
	
		
			
				|  |  |      while(lstPopPointer(&se->KnifeElements));
 | 
	
		
			
				|  |  |      la_FreeSelectData(se->sd); memFree(se);
 | 
	
	
		
			
				|  | @@ -1411,7 +1422,7 @@ int OPINV_Knife(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      int SelectMode=LA_CANVAS_SELECT_MODE_KNIFE;
 | 
	
		
			
				|  |  |      if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "loop_cut")){
 | 
	
		
			
				|  |  |          se->IsLoop=1; SelectMode=LA_CANVAS_SELECT_MODE_EDGES; }
 | 
	
		
			
				|  |  | -    la_PopulateSelectDataPrimitives(sd,mo,c,SelectMode);
 | 
	
		
			
				|  |  | +    la_PopulateSelectDataPrimitives(sd,mo,c,SelectMode,ex->SelectThrough);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(se->IsLoop){ strSafePrint(&a->RuntimeHint,"◧ Cut  ◨ Cancel"); }
 | 
	
		
			
				|  |  |      else{ strSafePrint(&a->RuntimeHint,"◧ Place Cut  ◨ Cancel  ⮨ Confirm"); }
 | 
	
	
		
			
				|  | @@ -1427,7 +1438,7 @@ int OPMOD_Knife(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      int changed=0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(e->Type==LA_R_MOUSE_DOWN || (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE)){
 | 
	
		
			
				|  |  | -        la_KnifeFinish(se,root); laNotifyUsers("tns.world"); return LA_FINISHED;
 | 
	
		
			
				|  |  | +        la_KnifeFinish(se,mo); laNotifyUsers("tns.world"); return LA_FINISHED;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(e->Type&LA_MOUSE_EVENT){
 | 
	
	
		
			
				|  | @@ -1451,7 +1462,7 @@ int OPMOD_Knife(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |              tnsInvalidateMeshBatch(mo); laNotifyUsers("tns.world");
 | 
	
		
			
				|  |  |              laRecordAndPush(0,"tns.world",se->IsLoop?"Loop Cut":"Knife Cut",TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        la_KnifeFinish(se,root); return LA_FINISHED;
 | 
	
		
			
				|  |  | +        la_KnifeFinish(se,mo); return LA_FINISHED;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      if(changed){
 |