|  | @@ -76,10 +76,16 @@ int OPINV_ToggleEdit(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      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; if(!mo) return 0;
 | 
	
		
			
				|  |  | -    if(mo->Base.Type!=TNS_OBJECT_MESH) return LA_CANCELED;
 | 
	
		
			
				|  |  | -    if(mo->Mode==TNS_MESH_EDIT_MODE) tnsMeshLeaveEditMode(mo); else tnsMeshEnterEditMode(mo);
 | 
	
		
			
				|  |  | -    laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Toggle edit mode", TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  | +    tnsObject* o=root->Active; if(!o) return 0;
 | 
	
		
			
				|  |  | +    char* ObType=0;
 | 
	
		
			
				|  |  | +    if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o; ObType="tns_mesh_object";
 | 
	
		
			
				|  |  | +        if(mo->Mode==TNS_MESH_EDIT_MODE) tnsMeshLeaveEditMode(mo); else tnsMeshEnterEditMode(mo);
 | 
	
		
			
				|  |  | +    }elif(o->Type==TNS_OBJECT_SHAPE){ tnsShapeObject* so=o; ObType="tns_shape_object";
 | 
	
		
			
				|  |  | +        if(so->Mode==TNS_MESH_EDIT_MODE) tnsShapeLeaveEditMode(so); else tnsShapeEnterEditMode(so);
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        return LA_CANCELED;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    laRecordInstanceDifferences(o, ObType); laPushDifferences("Toggle edit mode", TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  |      laNotifyUsers("tns.world");
 | 
	
		
			
				|  |  |      return LA_FINISHED_PASS;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -119,9 +125,9 @@ void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, laCanvasExtr
 | 
	
		
			
				|  |  |      tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      NVGcontext* vg=MAIN.CurrentWindow->nvg;
 | 
	
		
			
				|  |  | -    la3DObjectDrawExtra de={0}; de.W=w; de.H=h;
 | 
	
		
			
				|  |  | +    la3DObjectDrawExtra de={0}; de.W=w; de.H=h; de.PointScale=1.0f/LA_RH;
 | 
	
		
			
				|  |  |      tnsMatrix44d mview,mproj; tnsRootObject* ro=root;
 | 
	
		
			
				|  |  | -    if(ro && ro->Is2D){ la_SetCanvasOrtho(e,w,h); }
 | 
	
		
			
				|  |  | +    if(ro && ro->Is2D){ la_SetCanvasOrtho(e,w,h); de.PointScale=e->ZoomX; }
 | 
	
		
			
				|  |  |      else{ tnsApplyCameraView(w, h, camera, mview,mproj); tnsMultiply44d(de.mViewProj,mproj,mview); de.Is3D=1; }
 | 
	
		
			
				|  |  |      la_BeginNVG(vg,e,w,h,ro->Is2D);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -136,7 +142,7 @@ void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
 | 
	
		
			
				|  |  |      arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsMVert*));
 | 
	
		
			
				|  |  |      if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
 | 
	
		
			
				|  |  |      for(tnsMVert* v=mo->mv.pFirst;v;v=v->Item.pNext){
 | 
	
		
			
				|  |  | -        arrEnsureLength(&sd->RefsV, v->i, &sd->maxV, sizeof(tnsObject*));
 | 
	
		
			
				|  |  | +        arrEnsureLength(&sd->RefsV, v->i, &sd->maxV, sizeof(tnsMVert*));
 | 
	
		
			
				|  |  |          sd->RefsV[v->i]=v; sd->nextV=TNS_MAX2(v->i, sd->nextV);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      sd->nextV++;
 | 
	
	
		
			
				|  | @@ -150,32 +156,63 @@ void la_PopulateSelectEdges(MSelectData* sd, tnsMeshObject* mo){
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      sd->nextE++;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera, int WhatPrim, int SelectThrough){
 | 
	
		
			
				|  |  | +void la_PopulateSelectPoints(MSelectData* sd, tnsShapeObject* so){
 | 
	
		
			
				|  |  | +    sd->nextV=0;
 | 
	
		
			
				|  |  | +    arrEnsureLength(&sd->RefsV,sd->nextV,&sd->maxV,sizeof(tnsSPoint*));
 | 
	
		
			
				|  |  | +    if(so->Base.Type!=TNS_OBJECT_SHAPE||!so->Shapes.pFirst){ return; }
 | 
	
		
			
				|  |  | +    for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
 | 
	
		
			
				|  |  | +        for(tnsSPoint*sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
 | 
	
		
			
				|  |  | +            arrEnsureLength(&sd->RefsV, sd->nextV, &sd->maxV, sizeof(tnsSPoint*));
 | 
	
		
			
				|  |  | +            sd->RefsV[sd->nextV]=sp; sd->nextV++;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    sd->nextV++;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsObject* o, tnsCamera* camera, int WhatPrim, tnsObject* root, laCanvasExtra* e){
 | 
	
		
			
				|  |  |      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); }
 | 
	
		
			
				|  |  | -    if(DoEdges || Knife){ la_PopulateSelectEdges(sd,mo); }
 | 
	
		
			
				|  |  | +    tnsMeshObject* mo=o; tnsShapeObject* so=o;
 | 
	
		
			
				|  |  | +    if(o->Type==TNS_OBJECT_MESH){
 | 
	
		
			
				|  |  | +        if(DoVerts || Knife){ la_PopulateSelectVerts(sd,mo); }
 | 
	
		
			
				|  |  | +        if(DoEdges || Knife){ la_PopulateSelectEdges(sd,mo); }
 | 
	
		
			
				|  |  | +    }elif(o->Type==TNS_OBJECT_SHAPE){
 | 
	
		
			
				|  |  | +        la_PopulateSelectPoints(sd,so);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      int w=sd->Color->Width, h=sd->Color->Height;
 | 
	
		
			
				|  |  |      tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
 | 
	
		
			
				|  |  |      tnsEnableShaderv(T->SelectionShader);
 | 
	
		
			
				|  |  |      tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
 | 
	
		
			
				|  |  | -    tnsApplyCameraView(w,h,camera,0,0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    NVGcontext* vg=MAIN.CurrentWindow->nvg;
 | 
	
		
			
				|  |  | +    la3DObjectDrawExtra de={0}; de.W=w; de.H=h; de.PointScale=1.0f/LA_RH;
 | 
	
		
			
				|  |  | +    tnsMatrix44d mview,mproj; tnsRootObject* ro=root;
 | 
	
		
			
				|  |  | +    if(ro && ro->Is2D){ la_SetCanvasOrtho(e,w,h); de.PointScale=e->ZoomX; }
 | 
	
		
			
				|  |  | +    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);
 | 
	
		
			
				|  |  | -    tnsPushMatrix(); tnsApplyModelMatrix(mo->Base.GlobalTransform);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);
 | 
	
		
			
				|  |  | +    tnsPushMatrix(); tnsApplyModelMatrix(o->GlobalTransform);glEnable(GL_DEPTH_TEST);
 | 
	
		
			
				|  |  | +    if(o->Type==TNS_OBJECT_MESH){
 | 
	
		
			
				|  |  | +        if(!e->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(o->Type==TNS_OBJECT_MESH){
 | 
	
		
			
				|  |  | +        if(DoEdges || Knife){ tnsDrawBatch(mo->Batch, "edges_select",0,0); }
 | 
	
		
			
				|  |  | +        if(DoVerts || Knife){ tnsDrawBatch(mo->Batch, "verts_select",0,0); }
 | 
	
		
			
				|  |  | +    }elif(o->Type==TNS_OBJECT_SHAPE){
 | 
	
		
			
				|  |  | +        tnsEvaluatedInstance ei; memcpy(&ei.Mat,o->GlobalTransform,sizeof(tnsMatrix44d)); ei.Object=o;
 | 
	
		
			
				|  |  | +        tnsDrawShapePointsSelectionID(&ei,&de);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      tnsUniformUseOffset(T->SelectionShader,0);
 | 
	
		
			
				|  |  |      tnsPopMatrix();
 | 
	
		
			
				|  |  |      glDisable(GL_DEPTH_TEST);
 | 
	
		
			
				|  |  | -    tnsEnableShaderv(T->immShader);
 | 
	
		
			
				|  |  | +    nvgEndFrame(vg); tnsRestoreFromNanoVG(); tnsEnableShaderv(T->immShader);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_PadSelectionBuffer(uint8_t* buf, int w, int h, int sx, int sy, int ex, int ey, int real_endx){
 | 
	
		
			
				|  |  |      if(!sx&&!sy&&!ex&&!ey) return;
 | 
	
	
		
			
				|  | @@ -289,6 +326,9 @@ void la_DoMeshSelect(tnsMeshObject* mo, void* p, int WhatPrim, int DeselectAll,
 | 
	
		
			
				|  |  |      if(p){ if(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS) tnsMMeshSelectVert(mo,p,Select,Toggle);
 | 
	
		
			
				|  |  |          elif(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES) tnsMMeshSelectEdge(mo,p,Select,Toggle);  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +void la_DoShapeSelect(tnsShapeObject* so, void* p, int DeselectAll, int Select, int Toggle){
 | 
	
		
			
				|  |  | +    if(DeselectAll){ tnsShapeDeselectAll(so); } if(p) tnsShapeSelectPoint(so,p,Select,Toggle);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define LA_SELECT_MODE_BOX 1
 | 
	
		
			
				|  |  |  STRUCTURE(MSelectExtra){
 | 
	
	
		
			
				|  | @@ -308,13 +348,16 @@ int OPINV_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      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;
 | 
	
		
			
				|  |  | +    tnsObject* o=root->Active; tnsMeshObject* mo=o; tnsShapeObject* so=o;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      int is_geo=0, SelectMode=ex->SelectMode, ring_band=0;
 | 
	
		
			
				|  |  |      if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "toggle")){
 | 
	
		
			
				|  |  | -        if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | +        if(o && o->Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  |              if(tnsMMeshAnySelected(mo)) tnsMMeshDeselectAll(mo); else tnsMMeshSelectAll(mo);
 | 
	
		
			
				|  |  |              tnsInvalidateMeshBatch(mo); is_geo=1;
 | 
	
		
			
				|  |  | +        }elif(o && o->Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){ is_geo=1;
 | 
	
		
			
				|  |  | +            if(tnsShapeAnySelected(so)) tnsShapeDeselectAll(so); else tnsShapeSelectAll(so);
 | 
	
		
			
				|  |  | +            //tnsInvalidateMeshBatch(mo);
 | 
	
		
			
				|  |  |          }else{
 | 
	
		
			
				|  |  |              if(tnsAnyObjectsSelected(root)) tnsDeselectAllObjects(root); else tnsSelectAllObjects(root);
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -330,8 +373,8 @@ int OPINV_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      int DeselectAll=1;
 | 
	
		
			
				|  |  |      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, ex->SelectThrough);
 | 
	
		
			
				|  |  | +    if(o&&o->Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | +        la_PopulateSelectDataPrimitives(sd, mo, ex->ViewingCamera, SelectMode, root, ex);
 | 
	
		
			
				|  |  |          if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
 | 
	
		
			
				|  |  |              MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
 | 
	
		
			
				|  |  |              ex->OnX=e->x; ex->OnX=e->y;
 | 
	
	
		
			
				|  | @@ -345,6 +388,18 @@ int OPINV_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          tnsInvalidateMeshBatch(mo);
 | 
	
		
			
				|  |  |          laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Mesh selection",TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  | +    }elif(o&&o->Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | +        la_PopulateSelectDataPrimitives(sd, mo, ex->ViewingCamera, SelectMode, root, ex);
 | 
	
		
			
				|  |  | +        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
 | 
	
		
			
				|  |  | +            MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
 | 
	
		
			
				|  |  | +            ex->OnX=e->x; ex->OnX=e->y;
 | 
	
		
			
				|  |  | +            a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->mo=mo; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        int elemtype,id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH,&elemtype)-1;
 | 
	
		
			
				|  |  | +        void* p=la_SelectGetRef(sd,id,elemtype);
 | 
	
		
			
				|  |  | +        la_DoShapeSelect(mo, p, DeselectAll, 1, 1);
 | 
	
		
			
				|  |  | +        if(ring_band && p){ tnsShapeSelectRingFrom(mo,p,1,Append); }
 | 
	
		
			
				|  |  | +        laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Shape selection",TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  |      }else{
 | 
	
		
			
				|  |  |          la_PopulateSelectDataObjects(sd,root,ex);
 | 
	
		
			
				|  |  |          if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
 | 
	
	
		
			
				|  | @@ -366,7 +421,7 @@ int OPMOD_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      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;
 | 
	
		
			
				|  |  | +    tnsObject* o=root->Active; tnsMeshObject* mo=o; tnsShapeObject* so=o;
 | 
	
		
			
				|  |  |      MSelectExtra* se=a->CustomData;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(e->Type==LA_L_MOUSE_DOWN){ se->InSelect=1; ex->DrawCursor=2; ex->ClickedX=e->x; ex->ClickedY=e->y; laRedrawCurrentPanel(); }
 | 
	
	
		
			
				|  | @@ -381,7 +436,7 @@ int OPMOD_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      int is_geo=0;
 | 
	
		
			
				|  |  |      if(se->InSelect && e->Type==LA_L_MOUSE_UP){
 | 
	
		
			
				|  |  | -        if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | +        if(o && o->Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){ is_geo=1;
 | 
	
		
			
				|  |  |              la_DoMeshSelect(mo, 0, ex->SelectMode, DeselectAll, 0, 0);
 | 
	
		
			
				|  |  |              int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX-ui->L, ex->ClickedY-ui->U, e->x-ui->L, e->y-ui->U, &len);
 | 
	
		
			
				|  |  |              for(int i=0;i<len;i++){
 | 
	
	
		
			
				|  | @@ -389,7 +444,14 @@ int OPMOD_Select(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |                  la_DoMeshSelect(mo, p, ex->SelectMode, 0, !Remove, 0);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              tnsMMeshEnsureSelection(mo,ex->SelectMode);
 | 
	
		
			
				|  |  | -            tnsInvalidateMeshBatch(mo); is_geo=1;
 | 
	
		
			
				|  |  | +            tnsInvalidateMeshBatch(mo); 
 | 
	
		
			
				|  |  | +        }elif(o && o->Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){ is_geo=1;
 | 
	
		
			
				|  |  | +            la_DoShapeSelect(so, 0, DeselectAll, 0, 0);
 | 
	
		
			
				|  |  | +            int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX-ui->L, ex->ClickedY-ui->U, e->x-ui->L, e->y-ui->U, &len);
 | 
	
		
			
				|  |  | +            for(int i=0;i<len;i++){
 | 
	
		
			
				|  |  | +                int id=ids[i]-1; void* p=la_SelectGetRef(se->sd,id,ex->SelectMode==LA_CANVAS_SELECT_MODE_EDGES?TNS_MMESH_EDGE_BIT:0);
 | 
	
		
			
				|  |  | +                la_DoShapeSelect(so, p, 0, !Remove, 0);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }else{
 | 
	
		
			
				|  |  |              la_DoObjectSelect(se->root, 0, ex, DeselectAll, 0, 0);
 | 
	
		
			
				|  |  |              int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX, ex->ClickedY, e->x-ui->L, e->y-ui->U, &len);
 | 
	
	
		
			
				|  | @@ -428,13 +490,19 @@ STRUCTURE(MTOrigMVert){
 | 
	
		
			
				|  |  |      tnsVector3d origp;
 | 
	
		
			
				|  |  |      tnsMVert* mv;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  | +STRUCTURE(MTOrigSPoint){
 | 
	
		
			
				|  |  | +    tnsVector2d p;
 | 
	
		
			
				|  |  | +    tnsVector2d origp;
 | 
	
		
			
				|  |  | +    tnsSPoint* sp;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  STRUCTURE(MTransformData){
 | 
	
		
			
				|  |  |      tnsMatrix44d Delta;
 | 
	
		
			
				|  |  |      tnsMatrix44d ViewProjection;
 | 
	
		
			
				|  |  |      tnsVector4d Up,Right,Foward;
 | 
	
		
			
				|  |  |      tnsVector4d TCenter,TLCenter;
 | 
	
		
			
				|  |  |      int CenterX,CenterY; real Initial;
 | 
	
		
			
				|  |  | -    tnsObject* mo; tnsMatrix44d obmatinv,deltainv;
 | 
	
		
			
				|  |  | +    tnsObject* mo; tnsShapeObject* so;
 | 
	
		
			
				|  |  | +    tnsMatrix44d obmatinv,deltainv;
 | 
	
		
			
				|  |  |      tnsCamera* c; tnsObject* root;
 | 
	
		
			
				|  |  |      int w,h;
 | 
	
		
			
				|  |  |      void* Originals; int next,max;
 | 
	
	
		
			
				|  | @@ -511,10 +579,32 @@ int la_PopulateTransformVerticies(MTransformData* td, tnsMeshObject* mo){
 | 
	
		
			
				|  |  |      la_GetTransformCenter2D(td);
 | 
	
		
			
				|  |  |      return any;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +int la_PopulateTransformPoints(MTransformData* td, tnsShapeObject* so){
 | 
	
		
			
				|  |  | +    int any=0; td->so=so; td->next=0;
 | 
	
		
			
				|  |  | +    arrEnsureLength(&td->Originals, 0, &td->max, sizeof(MTOrigSPoint));
 | 
	
		
			
				|  |  | +    tnsInverse44d(td->obmatinv, so->Base.GlobalTransform);
 | 
	
		
			
				|  |  | +    tnsInverse44d(td->deltainv, so->Base.DeltaTransform);
 | 
	
		
			
				|  |  | +    for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){
 | 
	
		
			
				|  |  | +        for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
 | 
	
		
			
				|  |  | +            if(!(sp->flags&TNS_MESH_FLAG_SELECTED)) continue;
 | 
	
		
			
				|  |  | +            arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigSPoint));
 | 
	
		
			
				|  |  | +            MTOrigSPoint* to=arrElement(td->Originals, td->next, sizeof(MTOrigSPoint)); td->next++; to->sp=sp;
 | 
	
		
			
				|  |  | +            tnsVector3d tp; tnsVector3d fp={sp->p[0],sp->p[1],0};
 | 
	
		
			
				|  |  | +            tnsApplyTransform43d(tp, so->Base.GlobalTransform, fp);
 | 
	
		
			
				|  |  | +            tnsVectorSet2v(to->p,tp); tnsVectorSet2v(to->origp,sp->p); any++;
 | 
	
		
			
				|  |  | +            tnsVectorAccum2d(td->TCenter,to->p);
 | 
	
		
			
				|  |  | +            tnsVectorAccum2d(td->TLCenter,sp->p);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    tnsVectorMultiSelf2d(td->TCenter, 1.0f/any);
 | 
	
		
			
				|  |  | +    tnsVectorMultiSelf2d(td->TLCenter, 1.0f/any);
 | 
	
		
			
				|  |  | +    la_GetTransformCenter2D(td);
 | 
	
		
			
				|  |  | +    return any;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  void la_ApplyTranslation(MTransformData* td, int x, int y){
 | 
	
		
			
				|  |  |      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->Is2D || td->so){
 | 
	
		
			
				|  |  | +        use_delta[0]=x*(td->so?(1.0f/LA_RH):td->zoomx); use_delta[1]=-y*(td->so?(1.0f/LA_RH):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);
 | 
	
	
		
			
				|  | @@ -534,7 +624,23 @@ void la_ApplyTranslation(MTransformData* td, int x, int y){
 | 
	
		
			
				|  |  |          real dir=tnsDot3d(use_delta, lock, 0); tnsVectorMultiSelf3d(use_delta,(td->UserDeltaVal*dir<=0)?-1:1);
 | 
	
		
			
				|  |  |          td->DeltaVal=td->UserDeltaVal; 
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if(!td->mo){
 | 
	
		
			
				|  |  | +    if(td->mo){
 | 
	
		
			
				|  |  | +        tnsMakeTranslationMatrix44d(trans, LA_COLOR3(use_delta)); tnsMatrix44d final; 
 | 
	
		
			
				|  |  | +        if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,trans);
 | 
	
		
			
				|  |  | +        else tnsMultiply44d(final,trans,td->obmatinv);
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
 | 
	
		
			
				|  |  | +            tnsApplyTransform43d(to->mv->p, final, to->p);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
 | 
	
		
			
				|  |  | +    }elif(td->so){
 | 
	
		
			
				|  |  | +        tnsMakeTranslationMatrix44d(trans, LA_COLOR3(use_delta)); tnsMatrix44d final; 
 | 
	
		
			
				|  |  | +        if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,trans);
 | 
	
		
			
				|  |  | +        else tnsMultiply44d(final,trans,td->obmatinv);
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigSPoint* to=arrElement(td->Originals, i, sizeof(MTOrigSPoint));
 | 
	
		
			
				|  |  | +            tnsVector3d fp={to->p[0],to->p[1],0}, tp;
 | 
	
		
			
				|  |  | +            tnsApplyTransform43d(tp, final, fp); tnsVectorSet3v(to->sp->p,tp);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  |          for(int i=0;i<td->next;i++){
 | 
	
		
			
				|  |  |              MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
 | 
	
		
			
				|  |  |              if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
 | 
	
	
		
			
				|  | @@ -547,30 +653,15 @@ void la_ApplyTranslation(MTransformData* td, int x, int y){
 | 
	
		
			
				|  |  |                  else tnsMoveObjectGlobal(to->o, LA_COLOR3(use_delta));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -    }else{
 | 
	
		
			
				|  |  | -        tnsMakeTranslationMatrix44d(trans, LA_COLOR3(use_delta)); tnsMatrix44d final; 
 | 
	
		
			
				|  |  | -        if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,trans);
 | 
	
		
			
				|  |  | -        else tnsMultiply44d(final,trans,td->obmatinv);
 | 
	
		
			
				|  |  | -        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
 | 
	
		
			
				|  |  | -            tnsApplyTransform43d(to->mv->p, final, to->p);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_ApplyScale(MTransformData* td, int uix, int uiy){
 | 
	
		
			
				|  |  |      tnsMatrix44d trans; real d=tnsDistIdv2(uix,uiy,td->CenterX,td->CenterY); if(!td->Initial){ td->Initial=100; }
 | 
	
		
			
				|  |  |      real s=d/td->Initial; tnsVector3d gp;
 | 
	
		
			
				|  |  |      td->DeltaVal=s; if(td->UseUserDelta) td->DeltaVal=s=td->UserDeltaVal;
 | 
	
		
			
				|  |  | -    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));
 | 
	
		
			
				|  |  | -            if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
 | 
	
		
			
				|  |  | -            if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 0); else tnsGlobalMatrixChanged(to->o, 0);
 | 
	
		
			
				|  |  | -            if(td->CanvasDeltaMode) tnsScaleObjectDelta(to->o,s,s,s,LA_COLOR3(td->TCenter));
 | 
	
		
			
				|  |  | -            else tnsScaleObject(to->o, s,s,s, LA_COLOR3(td->TCenter));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }else{
 | 
	
		
			
				|  |  | -        tnsVector3d use_delta={s,s,s};
 | 
	
		
			
				|  |  | +    tnsMatrix44d t1,t2,t3,final; 
 | 
	
		
			
				|  |  | +    if(td->mo || td->so){
 | 
	
		
			
				|  |  | +        tnsVector3d use_delta={s,s,s};\
 | 
	
		
			
				|  |  |          if(td->LockAxis[0]>0){ use_delta[1]=use_delta[2]=1;}
 | 
	
		
			
				|  |  |          if(td->LockAxis[1]>0){ use_delta[0]=use_delta[2]=1;}
 | 
	
		
			
				|  |  |          if(td->LockAxis[2]>0){ use_delta[0]=use_delta[1]=1;}
 | 
	
	
		
			
				|  | @@ -578,26 +669,59 @@ void la_ApplyScale(MTransformData* td, int uix, int uiy){
 | 
	
		
			
				|  |  |          if(td->LockAxis[1]<0){ use_delta[1]=1; }
 | 
	
		
			
				|  |  |          if(td->LockAxis[2]<0){ use_delta[2]=1; }
 | 
	
		
			
				|  |  |          tnsMakeScaleMatrix44d(trans,LA_COLOR3(use_delta));
 | 
	
		
			
				|  |  | -        tnsMatrix44d t1,t2,t3; tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->TCenter)); tnsInverse44d(t2,t1);
 | 
	
		
			
				|  |  | -        tnsMatrix44d final; tnsMultiply44d(t3,t1,trans); tnsMultiply44d(t1,t3,t2);
 | 
	
		
			
				|  |  | +        tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->TCenter)); tnsInverse44d(t2,t1);
 | 
	
		
			
				|  |  | +        tnsMultiply44d(t3,t1,trans); tnsMultiply44d(t1,t3,t2);
 | 
	
		
			
				|  |  |          if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,t1);
 | 
	
		
			
				|  |  |          else tnsMultiply44d(final,t1,td->obmatinv);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(td->mo){
 | 
	
		
			
				|  |  |          for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
 | 
	
		
			
				|  |  |              tnsApplyTransform43d(to->mv->p, final, to->p);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
 | 
	
		
			
				|  |  | +    }elif(td->so){
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigSPoint* to=arrElement(td->Originals, i, sizeof(MTOrigSPoint));
 | 
	
		
			
				|  |  | +            tnsVector3d fp={to->p[0],to->p[1],0}, tp;
 | 
	
		
			
				|  |  | +            tnsApplyTransform43d(tp, final, fp); tnsVectorSet3v(to->sp->p,tp);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){
 | 
	
		
			
				|  |  | +            MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
 | 
	
		
			
				|  |  | +            if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
 | 
	
		
			
				|  |  | +            if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 0); else tnsGlobalMatrixChanged(to->o, 0);
 | 
	
		
			
				|  |  | +            if(td->CanvasDeltaMode) tnsScaleObjectDelta(to->o,s,s,s,LA_COLOR3(td->TCenter));
 | 
	
		
			
				|  |  | +            else tnsScaleObject(to->o, s,s,s, LA_COLOR3(td->TCenter));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  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; }
 | 
	
		
			
				|  |  | +    tnsMatrix44d t1,t2,t3,final;
 | 
	
		
			
				|  |  | +    if(td->Is2D || td->so){ 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; 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->mo){
 | 
	
		
			
				|  |  | +    if(td->mo||td->so){
 | 
	
		
			
				|  |  | +        tnsMakeRotationMatrix44d(trans, angle, LA_COLOR3(use_forward));
 | 
	
		
			
				|  |  | +        tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->UseLocal?td->TLCenter:td->TCenter)); tnsInverse44d(t2,t1);
 | 
	
		
			
				|  |  | +        tnsMultiply44d(t3,t1,trans); tnsMultiply44d(t1,t3,t2);
 | 
	
		
			
				|  |  | +        if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,t1);
 | 
	
		
			
				|  |  | +        else tnsMultiply44d(final,t1,td->obmatinv);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(td->mo){
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
 | 
	
		
			
				|  |  | +            tnsApplyTransform43d(to->mv->p, final, to->p);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
 | 
	
		
			
				|  |  | +    }elif(td->so){
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigSPoint* to=arrElement(td->Originals, i, sizeof(MTOrigSPoint));
 | 
	
		
			
				|  |  | +            tnsVector3d fp={to->p[0],to->p[1],0}, tp;
 | 
	
		
			
				|  |  | +            tnsApplyTransform43d(tp, final, fp); tnsVectorSet3v(to->sp->p,tp);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  |          for(int i=0;i<td->next;i++){
 | 
	
		
			
				|  |  |              MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
 | 
	
		
			
				|  |  |              if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
 | 
	
	
		
			
				|  | @@ -610,40 +734,36 @@ void la_ApplyRotation(MTransformData* td, int uix, int uiy){
 | 
	
		
			
				|  |  |                  else tnsRotateObjectGlobal(to->o,LA_COLOR3(use_forward),angle,LA_COLOR3(td->TCenter));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -    }else{
 | 
	
		
			
				|  |  | -        tnsMakeRotationMatrix44d(trans, angle, LA_COLOR3(use_forward));
 | 
	
		
			
				|  |  | -        tnsMatrix44d t1,t2,t3; tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->UseLocal?td->TLCenter:td->TCenter)); tnsInverse44d(t2,t1);
 | 
	
		
			
				|  |  | -        tnsMatrix44d final; tnsMultiply44d(t3,t1,trans); tnsMultiply44d(t1,t3,t2);
 | 
	
		
			
				|  |  | -        if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,t1);
 | 
	
		
			
				|  |  | -        else tnsMultiply44d(final,t1,td->obmatinv);
 | 
	
		
			
				|  |  | -        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
 | 
	
		
			
				|  |  | -            tnsApplyTransform43d(to->mv->p, final, to->p);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_CancelTransformObjects(MTransformData* td){
 | 
	
		
			
				|  |  | -    if(!td->mo){
 | 
	
		
			
				|  |  | +    if(td->mo){
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert)); tnsVectorCopy3d(to->origp,to->mv->p); }
 | 
	
		
			
				|  |  | +        tnsInvalidateMeshBatch(td->mo);
 | 
	
		
			
				|  |  | +    }elif(td->so){
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigSPoint* to=arrElement(td->Originals, i, sizeof(MTOrigSPoint)); tnsVectorCopy2d(to->origp,to->sp->p); }
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  |          for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
 | 
	
		
			
				|  |  |              if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
 | 
	
		
			
				|  |  |              memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
 | 
	
		
			
				|  |  |              if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 1);
 | 
	
		
			
				|  |  |              else tnsGlobalMatrixChanged(to->o, 1);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -    }else{
 | 
	
		
			
				|  |  | -        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert)); tnsVectorCopy3d(to->origp,to->mv->p); }
 | 
	
		
			
				|  |  | -        tnsInvalidateMeshBatch(td->mo);
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_RecordTransformDifferences(MTransformData* td){
 | 
	
		
			
				|  |  | -    if(!td->mo){
 | 
	
		
			
				|  |  | -        for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
 | 
	
		
			
				|  |  | -            laRecordInstanceDifferences(to->o, "tns_object");
 | 
	
		
			
				|  |  | -        } laPushDifferences(td->mode==LA_TRANSFORM_MODE_GRAB?"Moved objects":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotated objects":"Scaled objects", TNS_HINT_TRANSFORM);
 | 
	
		
			
				|  |  | -    }else{
 | 
	
		
			
				|  |  | +    if(td->mo){
 | 
	
		
			
				|  |  |          laRecordInstanceDifferences(td->mo, "tns_mesh_object");
 | 
	
		
			
				|  |  |          laPushDifferences(td->mode==LA_TRANSFORM_MODE_GRAB?"Moved primitives":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotated primitives":"Scaled primitives", TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  |          tnsInvalidateMeshBatch(td->mo);
 | 
	
		
			
				|  |  | +    }elif(td->so){
 | 
	
		
			
				|  |  | +        laRecordInstanceDifferences(td->so, "tns_shape_object");
 | 
	
		
			
				|  |  | +        laPushDifferences(td->mode==LA_TRANSFORM_MODE_GRAB?"Moved points":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotated points":"Scaled points", TNS_HINT_GEOMETRY);
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
 | 
	
		
			
				|  |  | +            laRecordInstanceDifferences(to->o, "tns_object");
 | 
	
		
			
				|  |  | +        } laPushDifferences(td->mode==LA_TRANSFORM_MODE_GRAB?"Moved objects":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotated objects":"Scaled objects", TNS_HINT_TRANSFORM);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_FreeTransformData(MTransformData* td){
 | 
	
	
		
			
				|  | @@ -683,7 +803,8 @@ 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; tnsRootObject*ro=root;
 | 
	
		
			
				|  |  | +    tnsObject* o=root->Active; tnsRootObject*ro=root;
 | 
	
		
			
				|  |  | +    tnsMeshObject* mo=o; tnsShapeObject* so=o;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      MTransformData* td=la_InitTransformData(
 | 
	
		
			
				|  |  |          ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c, ex->DeltaMode,
 | 
	
	
		
			
				|  | @@ -693,8 +814,10 @@ int la_InitTransform(laOperator* a, laEvent* e, int mode, int restore_type, int
 | 
	
		
			
				|  |  |      td->root=root;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      int ret=0;
 | 
	
		
			
				|  |  | -    if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | +    if(o && o->Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  |          if(la_PopulateTransformVerticies(td, mo)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
 | 
	
		
			
				|  |  | +    }if(o && o->Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){
 | 
	
		
			
				|  |  | +        if(la_PopulateTransformPoints(td, so)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
 | 
	
		
			
				|  |  |      }else{
 | 
	
		
			
				|  |  |          if(la_PopulateTransformObjects(td,root)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
 | 
	
		
			
				|  |  |          if(ret && restore_type){
 | 
	
	
		
			
				|  | @@ -1353,10 +1476,10 @@ int OPINV_Separate(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      return LA_FINISHED;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void la_PopulateSelectedMeshObjects(tnsObject* root, laListHandle* l){
 | 
	
		
			
				|  |  | -    if(root->Type==TNS_OBJECT_MESH && root->Flags&TNS_OBJECT_FLAGS_SELECTED){ lstAppendPointer(l,root); }
 | 
	
		
			
				|  |  | +void la_PopulateSelectedObjects(tnsObject* root, laListHandle* l, int FilterType){
 | 
	
		
			
				|  |  | +    if(root->Flags&TNS_OBJECT_FLAGS_SELECTED){ if(root->Type && ((!FilterType) || root->Type==FilterType)) lstAppendPointer(l,root); }
 | 
	
		
			
				|  |  |      for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
 | 
	
		
			
				|  |  | -        la_PopulateSelectedMeshObjects(lip->p, l);
 | 
	
		
			
				|  |  | +        la_PopulateSelectedObjects(lip->p, l, FilterType);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  int OPINV_Combine(laOperator *a, laEvent *e){
 | 
	
	
		
			
				|  | @@ -1367,7 +1490,7 @@ int OPINV_Combine(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode==TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    laListHandle pending={0}; la_PopulateSelectedMeshObjects(root,&pending);
 | 
	
		
			
				|  |  | +    laListHandle pending={0}; la_PopulateSelectedObjects(root,&pending,TNS_OBJECT_MESH);
 | 
	
		
			
				|  |  |      tnsMeshObject* o; while(o=lstPopPointer(&pending)){ if(o==mo || o->Mode==TNS_MESH_EDIT_MODE) continue;
 | 
	
		
			
				|  |  |          if(tnsMergeMeshObjects(mo, o)) ran++;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1386,12 +1509,16 @@ int OPINV_Duplicate(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
 | 
	
		
			
				|  |  |      tnsMeshObject* mo=root->Active; int ran=0;
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode==TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
 | 
	
		
			
				|  |  | +    if(!mo || mo->Mode==TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    laListHandle pending={0}; la_PopulateSelectedMeshObjects(root,&pending);
 | 
	
		
			
				|  |  | +    laListHandle pending={0}; la_PopulateSelectedObjects(root,&pending,0);
 | 
	
		
			
				|  |  |      tnsMeshObject* o; tnsMeshObject* no; laListItemPointer* lip;
 | 
	
		
			
				|  |  |      for(lip=pending.pFirst;lip;lip=lip->pNext){ o=lip->p; o->Base.EditDuplicateTemp=0; if (o->Mode == TNS_MESH_EDIT_MODE) continue;
 | 
	
		
			
				|  |  | -        if (no = tnsDuplicateMeshObject(o)){ o->Base.EditDuplicateTemp=no;
 | 
	
		
			
				|  |  | +        if(o->Base.Type==TNS_OBJECT_MESH) no = tnsDuplicateMeshObject(o);
 | 
	
		
			
				|  |  | +        elif(o->Base.Type==TNS_OBJECT_SHAPE) no = tnsDuplicateShapeObject(o);
 | 
	
		
			
				|  |  | +        elif(o->Base.Type==TNS_OBJECT_INSTANCER) no = tnsDuplicateShapeObject(o);
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        if(no){ o->Base.EditDuplicateTemp=no;
 | 
	
		
			
				|  |  |              no->Base.Flags |= TNS_OBJECT_FLAGS_SELECTED; o->Base.Flags &= (~TNS_OBJECT_FLAGS_SELECTED);
 | 
	
		
			
				|  |  |              if (mo == o) { memAssignRef(root, &root->Active, no); } ran++;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -1403,7 +1530,7 @@ int OPINV_Duplicate(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      while(o=lstPopPointer(&pending)){ o->Base.EditDuplicateTemp=0; }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      if(ran){
 | 
	
		
			
				|  |  | -        laRecordAndPush(0,"tns.world","Merge mesh objects",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
 | 
	
		
			
				|  |  | +        laRecordAndPush(0,"tns.world","Duplicated objects",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
 | 
	
		
			
				|  |  |          if(la_InitTransform(a,e,LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      
 | 
	
	
		
			
				|  | @@ -1536,7 +1663,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,ex->SelectThrough);
 | 
	
		
			
				|  |  | +    la_PopulateSelectDataPrimitives(sd,mo,c,SelectMode,root,ex);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(se->IsLoop){ strSafePrint(&a->RuntimeHint,"◧ Cut  ◨ Cancel"); }
 | 
	
		
			
				|  |  |      else{ strSafePrint(&a->RuntimeHint,"◧ Place Cut  ◨ Cancel  ⮨ Confirm"); }
 |