3D Placement Gizmo?

Miscellaneous Forums/General Discussion/3D Placement Gizmo?

Does anyone have code for 3D Placement ( position, scale and rotation, ideally ) gizmos, such as those found in 3dsMax, etc? Doesn't really matter to me if it's Blitz3D, BlitzMax or whatever, which is why I didn't post in a language-specific forum.

I wrote my own gizmos nearly a year ago and there's something about them which is clumsy, but I can't quite put my finger on what's wrong with them. They just don't "feel" right, and I'm not mad keen to bury myself in code I haven't touched for a year to find out. So I was hoping someone might have already done this for a dropper, modeller, level editor, whatever, and be prepared to share.

Do you need code or a program to do your job. Can you give us more details?

I can't offer you any code, but I can provide my usual rambling on it.

Gizmos are fairly simple- when you begin dragging any part of one, you should treat the mouse as if it were moving along a 3D plane aligned to where the gizmo is moving. E.g., dragging X would use a plane aligned along the XZ axises and based on the mouse's position on (so to speak) the plane, set it to the mouse's X position. Y would be YX (or YZ, or pick the one closest to the camera's view direction), Z would be ZX, etc. Picking which plane for single axises to use is probably best decided based on your camera's view direction, rather than hard-coding a specific one.

Hopefully that made something close to sense.

Short version:
1. Select axis
2. Align plane to axis (based on view direction where necessary)
3. Project 2D mouse onto 3D plane
4. Use the value of the projected point to set the new value

I had a mode switch on my gizmo, that allowed you to work in global or local mode. I'll try and find my gizmo code for you. It's blitz3d stuff.

I did something very simlar to noel. I had a 3d model of a gizmo, with different meshes. Upon clicking the mesh, i checked to see what mesh was being picked, then translated the mouse movement to either rotation, movement or scaling, just as you would for moving a slider. Remember to constantly centre the mouse pointer ^_^.

I didn't parent my mesh to the camera, so it could rotate freely, but made sure it was always positioned at the same distance in front of the camera. I think i ran into problems with the gizmo sometimes overlapping geometry, which only prove to be a problem when picking the gizmo.

I also experimented which no gizmo and placing a simple sphere at the selection centre. Dragging that, moved the mesh along the axis the camera was nearest aligned too. Again i had a mode button, where you could drag the mesh in the direction the camera was facing instead.

Damien did the Gizmo's for flowed, involved a lot of matrix math and quats to get it to work right. Was a really good exercise in learning some pretty important 3D math for game dev outside of blitz3D. He never had to learn it before because blitz3D does everything for you. So a lot really depends on the language your using.

Yaw, pitch and rotate in ogre work fine most of the time, so I'm not 100% sure why the complicated stuff was necessary, but the results were much better. Seems that the math involved is pretty tricky, good luck with finding a solution.

The biggest problem we had was a kind of floating point drift, where multplying matrices didn't quite add up, so we got some funny stretching behaviours. Ended up being a really basic problem that we were not familiar with. You just had to normalize the quats to get accurate rotations.

That was the one thing that messed our gizmos up for a while.

Yeah, in Blitz3D you can just use a Local switch on the translate/move calls, but outside of blitz you need to transform local/world space on your own. Requires Matrix math knowledge. Luckily ogre has that down already so it was jus thard figuring out what formula to use. I went the whole way and looked at matrix math and got a better understanding of the whole thing.

in blitz3d i believe you could just align a plane to the camera and mousepick it, and use the coords to move the object.

I can't find the gizmo version, but do you want the other version based on dragging and rotating?

here the class of gizmo of my editor (ediTable, Bmax+minib3D):


is not powerfull like 3dsmax ones, but I find it quite comfortable too...

Type tGizmo
 
 'status flags
 Field using:Int
 Field mode:String = "MOVE"
 
 'main entities
 Field entity:TEntity
 Field entityScale:TEntity
 Field pivotRotate:TEntity
 
 'gizmo handles
 Field arrow :TMesh[3]     'move / cone
 Field arrowR:TMesh[3]     'rotate / sphere
 Field arrowS:TMesh[3]     'scale / cube
 Field planeM:TMesh[3]     'move2axis / plane
 
 'projection variables 
 Field CX2D:Int      , CY2D:Int      '2Dcoords of center of gizmo
 Field AX2D:Int[3]   , AY2D:Int[3]   '2Dcoords of arrow
 Field PrjX:Int[3]   , PrjY:Int[3]   '2Dcoords of arrow mesh
 Field VX2D:Float[3] , VY2D:Float[3] '2Dcoords of unitary vector of axis
 
 Field showLines:Int
 
Rem 
  ===========================================================================================
  bbdoc: create:tGizmo() - ediTable Gizmo 
  about: create a gizmo
  ===========================================================================================
End Rem 
 Function create:tGizmo() 
    Local temp:tGizmo = New tGizmo
	'create the main entities----------------------------------------------------------------
	temp.entity = CreatePivot() 
	temp.pivotRotate = CreatePivot(temp.entity) 
	temp.entityScale = CreatePivot(temp.entity) 
 
	'create the handles----------------------------------------------------------------------
	For Local i:Int = 0 To 2
		temp.arrow[i] = CreateCone(8, True, temp.entityScale) 
			ScaleEntity (temp.arrow[i] , 0.11, 0.11, 0.11)  ; EntityOrder (temp.arrow[i] , - 100)
			EntityPickMode (temp.arrow[i] , 2)
 
		temp.arrowR[i] = CreateSphere(6, temp.entityScale) 
			ScaleEntity (temp.arrowR[i] , 0.08, 0.08, 0.08) ; EntityOrder (temp.arrowR[i] , - 99)
			EntityPickMode (temp.arrowR[i] , 2)
 
		temp.arrowS[i] = CreateCube(temp.entityScale) 
			ScaleEntity (temp.arrowS[i] , 0.06, 0.06, 0.06) ; EntityOrder (temp.arrowS[i] , - 98)
			EntityPickMode (temp.arrowS[i] , 2)
 
		temp.planeM[i] = CreateCube(temp.entityScale) 
			ScaleEntity (temp.planeM[i] , 0.4, 0.001, 0.4)  ; EntityOrder (temp.planeM[i] , - 97)
			EntityPickMode (temp.planeM[i] , 2 ) ; EntityAlpha (temp.planeM[i] , 0.5)
	Next
 
	'initialize the handles -----------------------------------------------------------------
	MoveEntity (temp.arrow[0]  , - 2  , 0, 0 ); MoveEntity (temp.arrow[1]  , 0 , 2  , 0 ); MoveEntity (temp.arrow[2]  , 0 , 0, 2)
	MoveEntity (temp.arrowR[0] , - 1.5, 0, 0 ); MoveEntity (temp.arrowR[1] , 0 , 1.5, 0 ); MoveEntity (temp.arrowR[2] , 0 , 0, 1.5)
	MoveEntity (temp.arrowS[0] , - 1  , 0, 0 ); MoveEntity (temp.arrowS[1] , 0 , 1  , 0 ); MoveEntity (temp.arrowS[2] , 0 , 0, 1)
	MoveEntity (temp.planeM[0] ,   0  , 1, 1 ); MoveEntity (temp.planeM[1] , -1, 0  , 1 ); MoveEntity (temp.planeM[2] , -1, 1, 0)
 
	RotateEntity (temp.arrow[0]  , 0 , 0, 90)
	RotateEntity (temp.arrow[2]  , 90, 0, 0)
    RotateEntity (temp.planeM[0] , 0 , 0, 90)
	RotateEntity (temp.planeM[2] , 90, 0, 0)
 
	EntityColor (temp.arrow[0]  , 255, 0, 0) ; EntityColor (temp.arrow[1]  , 0, 255, 0) ; EntityColor (temp.arrow[2]  , 0, 0, 255)
	EntityColor (temp.arrowR[0] , 255, 0, 0) ; EntityColor (temp.arrowR[1] , 0, 255, 0) ; EntityColor (temp.arrowR[2] , 0, 0, 255)
	EntityColor (temp.arrowS[0] , 255, 0, 0) ; EntityColor (temp.arrowS[1] , 0, 255, 0) ; EntityColor (temp.arrowS[2] , 0, 0, 255)
	EntityColor (temp.planeM[0] , 255, 0, 0) ; EntityColor (temp.planeM[1] , 0, 255, 0) ; EntityColor (temp.planeM[2] , 0, 0, 255)
 
	Return temp	
 End Function
 
Rem 
  ===========================================================================================
  bbdoc: update() - ediTable Gizmo 
  about: update 3D
  ===========================================================================================
End Rem  
 Method update() 
    'memorize the coords---------------------------------------------------------------------
    Local coordArray:Float[4] 
          coordArray[0] = 0  'X
          coordArray[1] = 0  'Y
          coordArray[2] = 0  'Z
          coordArray[3] = 0  'COUNT
 
    'gizmo controll offset variables---------------------------------------------------------
    Local Dx:Float  = 0.0  ; Local Dy:Float  = 0.0  ; Local Dz:Float  = 0.0
    Local DAx:Float = 0.0  ; Local DAy:Float = 0.0  ; Local DAz:Float = 0.0
    Local DSx:Float = 0    ; Local DSy:Float = 0    ; Local DSz:Float = 0
 
    'update the gizmo size (in function of distance from camera------------------------------
	Local DistanceFromCamera:Float = 5
	If(ViewMngr.View[viewMngr.SelectedView].prospective   = "3D") 
      DistanceFromCamera = EntityDistance(entity, ViewMngr.View[ViewMngr.SelectedView].CAMERA) 
	Else
      DistanceFromCamera = 5 / (ViewMngr.View[ViewMngr.SelectedView].CAMERA.zoom*4)
	EndIf
	ScaleEntity Self.entityScale, DistanceFromCamera / 5, DistanceFromCamera / 5, DistanceFromCamera / 5
	'check picked handle --------------------------------------------------------------------
    If(Using = 0) 
      'and set mode/using
      _pickManage(arrow , 0, "MOVE",   1); _pickManage(arrow , 1, "MOVE",   2) ; _pickManage(arrow, 2 , "MOVE",   3) 
      _pickManage(arrowR, 0, "ROTATE", 1); _pickManage(arrowR, 1, "ROTATE", 2) ; _pickManage(arrowR, 2, "ROTATE", 3) 		
      _pickManage(arrowS, 0, "SCALE",  1); _pickManage(arrowS, 1, "SCALE",  2) ; _pickManage(arrowS, 2, "SCALE",  3) 		
      _pickManage_invertFX(planeM, 0, "MOVE", 4) ; _pickManage_invertFX(planeM, 1, "MOVE", 5) ; _pickManage_invertFX(planeM, 2, "MOVE", 6) 
    EndIf
 
    Local distInc:Float=DistanceFromCamera/10.0	  
    RotateEntity PivotRotate,EntityPitch(PivotRotate) mod 360,EntityYaw(PivotRotate) mod 360,EntityRoll(PivotRotate) mod 360,1  
 
    'do what must do according to picked handle ----------------------------------------------
    'X Handles 
	If(Using = 1 Or using = 5 Or using = 6) 
      Local OffX:Float      = -(AX2D[0] - CX2D) / 100.00
      Local OffY:Float      = -(AY2D[0] - CY2D) / 100.00
      Local angle:Float     = ATan2((VY2D[0] - CY2D), (VX2D[0] - CX2D)) 
      Local modMove:Float   = (ProgMngr.Mouse.speedx * Cos(angle) * distInc) / 3.00 + (ProgMngr.Mouse.speedy * Sin(angle) * distInc) / 3.00
      Local modRotate:Float = (ProgMngr.Mouse.speedx * Cos(angle+90) * distInc) / 3.00 + (ProgMngr.Mouse.speedy * Sin(angle+90) * distInc) / 3.00
 
      If(mode = "MOVE")   Then  MoveEntity(entity, - modMove / 10.00, 0, 0)       ;     Dx = Dx + modMove / 10.00
      If(mode = "ROTATE") Then  RotateEntity(PivotRotate,(EntityPitch(PivotRotate)+ modRotate) mod 360,EntityYaw(PivotRotate) mod 360,EntityRoll(PivotRotate) mod 360,1)
      If(mode = "SCALE")  Then  DSx = DSx + modMove/10.00
    EndIf
    'Y Handles
    If(Using = 2 Or using = 4 Or using = 6) 
      Local OffX:Float      = -(AX2D[1] - CX2D )/ 100.00
      Local OffY:Float      = -(AY2D[1] - CY2D) / 100.00
      Local angle:Float     = ATan2((VY2D[1] - CY2D), (VX2D[1] - CX2D)) 
      Local modMove:Float   = (ProgMngr.Mouse.speedx * Cos(angle) * distInc) / 3.00 + (ProgMngr.Mouse.speedy * Sin(angle) * distInc) / 3.00
      Local modRotate:Float = (ProgMngr.Mouse.speedx * Cos(angle+90) * distInc) / 3.00 + (ProgMngr.Mouse.speedy * Sin(angle+90) * distInc) / 3.00
 
      If(mode = "MOVE")   Then  MoveEntity(entity, 0, modMove / 10.00, 0)         ;     Dy = Dy + modMove / 10.00
      If(mode = "ROTATE") Then  RotateEntity(PivotRotate, EntityPitch(PivotRotate) mod 360, Int(EntityYaw(PivotRotate) + modRotate) mod 360, EntityRoll(PivotRotate) mod 360, 1)
      If(mode = "SCALE")  Then  DSy = DSy + modMove/10.00
	EndIf
    'Z Handles
    If(Using = 3 Or using = 4 Or using = 5) 
      Local OffX:Float = -(AX2D[2] - CX2D) / 100.00
      Local OffY:Float = -(AY2D[2] - CY2D) / 100.00
      Local angle:Float = ATan2((VY2D[2] - CY2D), (VX2D[2] - CX2D)) 
      Local modMove:Float = (ProgMngr.Mouse.speedx * Cos(angle) * distInc) / 3.00 + (ProgMngr.Mouse.speedy * Sin(angle) * distInc) / 3.00
      Local modRotate:Float = (ProgMngr.Mouse.speedx * Cos(angle+90) * distInc) / 3.00 + (ProgMngr.Mouse.speedy * Sin(angle+90) * distInc) / 3.00
      If(mode = "MOVE")   Then  MoveEntity(entity, 0, 0, modMove / 10.00)         ;     Dz = Dz + modMove / 10.00
      If(mode = "ROTATE") Then  RotateEntity(PivotRotate, EntityPitch(PivotRotate) mod 360, EntityYaw(PivotRotate) mod 230, Int(EntityRoll(PivotRotate) + modRotate) mod 360, 1)
      If(mode = "SCALE")  Then  DSz = DSz + modMove/10.00
	EndIf
 
    RotateEntity PivotRotate,Int(EntityPitch(PivotRotate) mod 360),Int(EntityYaw(PivotRotate) mod 360),Int(EntityRoll(PivotRotate) mod 360),1  
    'manage parents-----------------------------------------------------------------------------
    For Local kk:String = EachIn SceneMngr.ObjMap.keys() 	
     If(Instr(kk,".")<=0)
       Local vTemp:VarTypeI=VarTypeI(SceneMngr.ObjMap.ValueForKey(kk))	
       vTemp.UnparentAllMesh()
     EndIf 
    Next
 
 
	'mode selection-----------------------------------------------------------------------------
    If(mode="ROTATE") 
     For Local kk:String = EachIn SceneMngr.Selected.keys() 
      If(Instr(kk,".")<=0)
        Local vTemp:VarTypeI=VarTypeI(SceneMngr.Selected.ValueForKey(kk))	
        vTemp.setAngleAllMesh(0,0,0)
        vTemp.parentAllMesh(PivotROTATE)
        vTemp.setAngleAllMesh(vTemp.ROTX,vTemp.ROTY,vTemp.ROTZ)
      EndIf 
     Next  
    EndIf		 
 
    If(mode="MOVE") 	
     For Local kk:String = EachIn SceneMngr.Selected.keys()
      If(Instr(kk,".")<=0)
       Local vTemp:VarTypeI=VarTypeI(SceneMngr.Selected.ValueForKey(kk))
        CoordArray = vTemp.getCoordsAllMesh(CoordArray) 
	    vTemp.setCoordsAllMesh(- Dx, Dy, Dz) 
	  EndIf
     Next 
    EndIf
 
    If(mode = "SCALE") 
     For Local kk:String = EachIn SceneMngr.Selected.keys() 
      If(Instr(kk,".")<=0)
        Local vTemp:VarTypeI=VarTypeI(SceneMngr.Selected.ValueForKey(kk))	
        vTemp.setScaleAllMesh(DSx, DSy, DSz) 
      EndIf 
     Next 
    EndIf
 
	If(coordArray[3]>0)' And mode="MOVE")
	   PositionEntity entity,CoordArray[0]/coordArray[3],CoordArray[1]/coordArray[3],CoordArray[2]/coordArray[3]
	EndIf
 
 
	If(Not ProgMngr.Mouse.Down[1])
	  Using=0
	EndIf
 
    'Projection update!-------------------------------------------------------------------------
     Local vpx:Int = ViewMngr.View[ViewMngr.SelectedView].x
	 Local vpy:Int = ViewMngr.View[ViewMngr.SelectedView].y
	 Local vpw:Int = vpx + ViewMngr.View[ViewMngr.SelectedView].W
	 Local vph:Int = vpy + ViewMngr.View[ViewMngr.SelectedView].H
 
	 'Center
     CameraProject ViewMngr.View[ViewMngr.SelectedView].Camera,EntityX(entity),EntityY(entity),EntityZ(entity)
 
	 CX2D = vpx + ProjectedX() 
	 CY2D = vpy + ProjectedY() 
 
	 If(CX2D > vpw) Then CX2D = vpw
	 If(CX2D < vpx) Then CX2D = vpx
	 If(CY2D > vph) Then CY2D = vph
	 If(CY2D < vpy) Then CY2D = vpy
 
	 'Extreme of axis
	 Local vectMod:Float = DistanceFromCamera / 2
     CameraProject ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(entity) - vectMod, EntityY(entity), EntityZ(entity) 
     AX2D[0] = vpx + ProjectedX()  ;  AY2D[0] = vpy + ProjectedY() 
     CameraProject ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(entity), EntityY(entity) + vectMod, EntityZ(entity) 
     AX2D[1] = vpx + ProjectedX()  ;  AY2D[1] = vpy + ProjectedY() 
     CameraProject ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(entity), EntityY(entity), EntityZ(entity) + vectMod
     AX2D[2] = vpx + ProjectedX()  ;  AY2D[2] = vpy + ProjectedY() 
 
	 'Unitary axist vector
     vectMod:Float = 10
     CameraProject (ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(entity) - vectMod, EntityY(entity), EntityZ(entity) )
     VX2D[0] = vpx + ProjectedX() ; VY2D[0] = vpy + ProjectedY() 
     CameraProject (ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(entity), EntityY(entity) + vectMod, EntityZ(entity) )
     VX2D[1] = vpx + ProjectedX() ; VY2D[1] = vpy + ProjectedY() 
     CameraProject (ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(entity), EntityY(entity), EntityZ(entity) + vectMod )
     VX2D[2] = vpx + ProjectedX() ; VY2D[2] = vpy + ProjectedY() 
 
 
	 showLines=False
	 'GizmoPoints
	 If(EntityInView(entity,ViewMngr.View[ViewMngr.SelectedView].CAMERA) )
      CameraProject (ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(Arrow[0] , True), EntityY(Arrow[0] , True), EntityZ(Arrow[0] , True) )
      PrjX[0] = ViewMngr.View[ViewMngr.SelectedView].x + ProjectedX()   ;  PrjY[0] = ViewMngr.View[ViewMngr.SelectedView].y + ProjectedY() 
      CameraProject (ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(Arrow[1] , True), EntityY(Arrow[1] , True), EntityZ(Arrow[1] , True) )
      PrjX[1] = ViewMngr.View[ViewMngr.SelectedView].x + ProjectedX()   ;  PrjY[1] = ViewMngr.View[ViewMngr.SelectedView].y + ProjectedY() 
      CameraProject (ViewMngr.View[ViewMngr.SelectedView].CAMERA, EntityX(Arrow[2] , True), EntityY(Arrow[2] , True), EntityZ(Arrow[2] , True) )
      PrjX[2] = ViewMngr.View[ViewMngr.SelectedView].x + ProjectedX()   ;  PrjY[2] = ViewMngr.View[ViewMngr.SelectedView].y + ProjectedY() 
      showLines=True
	 EndIf
 
 End Method
 
Rem 
  ===========================================================================================
  bbdoc: update2D() - ediTable Gizmo 
  about: update 2D
  ===========================================================================================
End Rem  
 Method update2D() 
     'Projection update!-------------------------------------------------------------------------
 
 
    SetViewport ViewMngr.View[ViewMngr.SelectedView].x, ViewMngr.View[ViewMngr.SelectedView].y + 32, ViewMngr.View[ViewMngr.SelectedView].W, ViewMngr.View[ViewMngr.SelectedView].h - 64
    If(Using > 0) 
     DrawText "(" + EntityX(SceneMngr.gizmo.entity) + "," + EntityY(SceneMngr.gizmo.entity) + "," + EntityZ(SceneMngr.gizmo.entity) + ")", SceneMngr.gizmo.CX2D - 100, SceneMngr.gizmo.CY2D + 10
    EndIf
 
	glEnable(GL_LINE_SMOOTH)   	'Quick antaliasing hack
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) 
    glLineWidth(1.0) 
 
	If(showLines)
	 If(ViewMngr.view[ViewMngr.SelectedView].onLeft(PrjX[0],PrjY[0]) Or ViewMngr.view[ViewMngr.SelectedView].onLeft(CX2D, CY2D))	  
     SetColor 255,0,0
      DrawText "X", SceneMngr.gizmo.AX2D[0] , SceneMngr.gizmo.AY2D[0] 
      DrawLine CX2D, CY2D, PrjX[0] , PrjY[0] 
	 EndIf
 
	 If(ViewMngr.view[ViewMngr.SelectedView].onLeft(PrjX[1],PrjY[1]) Or ViewMngr.view[ViewMngr.SelectedView].onLeft(CX2D, CY2D))	 		   
     SetColor 0,255,0
      DrawText "Y", SceneMngr.gizmo.AX2D[1] , SceneMngr.gizmo.AY2D[1] 
      DrawLine CX2D, CY2D, PrjX[1] , PrjY[1] 
 	 EndIf
 
	 If(ViewMngr.view[ViewMngr.SelectedView].onLeft(PrjX[2],PrjY[2]) Or ViewMngr.view[ViewMngr.SelectedView].onLeft(CX2D, CY2D))	 		   
     SetColor 0,0,255
      DrawText "Z", SceneMngr.gizmo.AX2D[2] , SceneMngr.gizmo.AY2D[2] 
      DrawLine CX2D, CY2D, PrjX[2] , PrjY[2] 
	 EndIf
	EndIf
    'backsetting		   
    SetColor 255, 255, 255
    glDisable(GL_LINE_SMOOTH) 
    SetViewport 0,0,ScreenX,ScreenY
 
 End Method
 
Rem 
  ===========================================================================================
  bbdoc: private pickManage() - ediTable Gizmo 
  about: pickManage
  ===========================================================================================
End Rem   
 Method _pickManage(ent:tEntity[] , dir:Int, resMode:String = "MOVE", resUsing:Int = 1) 
   '----------------------------------------------------
	 If(PickedEntity() = ent[dir] ) 
	   EntityAlpha ent[dir] , 0.2
	   If(ProgMngr.Mouse.Down[1] ) Then Using = resUsing ; mode = resMode
	 Else
	   EntityAlpha ent[dir] , 1
	 EndIf
 End Method
 
Rem 
  ===========================================================================================
  bbdoc: private pickManage_invertFX() - ediTable Gizmo 
  about: pickManage variant
  ===========================================================================================
End Rem 
 Method _pickManage_invertFX(ent:tEntity[] , dir:Int, resMode:String = "MOVE", resUsing:Int = 1) 
   '----------------------------------------------------
	 If(PickedEntity() = ent[dir] ) 
	   EntityAlpha ent[dir] , 0.8
	   If(ProgMngr.Mouse.Down[1] ) Then Using = resUsing ; mode = resMode
	 Else
	   EntityAlpha ent[dir] , 0.4
	 EndIf
 End Method
 
 
EndType

but is a bit messed up and have a lot of references to other class of program..

Wow, last time I checked this thread there were zero replies, and now look at it. Thanks everyone. I'm pretty sure my maths is correct. If my maths was wrong, it wouldn't work properly and it does. It's just the feel isn't right for me. I'm just not sure what is causing said "feel". In a certain sense, I actually think the feel was better when the math wasn't right. Perhaps I should have uploaded a demo and asked for feedback, but that isn't really practical right now.

Thank you Z4g0, I'll have a good dig around in your code and see if I can spot anything which will benefit my version.

Ross, I'd very much appreciate it. I hadn't thought about dragging for positioon, but I did add a drag and rotate mode which I'd like to improve.

Ok, here it is.

http://www.rosscrooks.pwp.blueyonder.co.uk/editor1.zip

I have included a userlib folder for the userlibs required. They are for the file requestor code.

A few point for usage.

The camera only drags to move when holding and dragging on the gizmo. Don't ask why... can't remember :D I forgot to hidemousepointer too, as i run it in full screen mode.

You best working in GLOBAL mode. There are buttons at the bottom to switch modes.

Left mouse button when dragging operates the X/Z axis. Right mouse button operates the Y axis.

You can lock an axis so only that axis gets effected, using the XYZ buttons, next to the padlock.

You drag the camera by holding the mouse button down for half a second. Holding in the middle mouse button rotates the view.

Sorry, controls are very clunky as i was messing about with them. As you can see, the only point in the gizmo currently in to choose a mid point for scaling and rotating. I was in the middle of changing everything about a year ago. Never got back to it :o( I have include a models folder so you can open meshes from within the app and muck about with them.

Hope some of that helps :o)

That code i posted any help Gab?

Thanks Ross. I haven't been able to work at all today ( don't ask! ) but I should get plenty of time tomorrow so I'm going to give it a concerted effort then.