PDA

View Full Version : Moving a viewport by dragging the mouse.



chronozphere
25-03-2009, 08:29 PM
Hi everyone

Glad to see PGD becoming an active community again. To stir things up more, i have an interesting question for you. ;)

I'm working on an UV-mapping tool and i want to be able to move the viewport by dragging the right mouse. I mean that when start to drag in the viewport, the coordinate system will stick to my mouse so i can move around and look at different area's.

This is my attempt:


//DragMoving indicates whether we are moving by dragging the mouse
//UVPos is the UV-position of the viewport (UV coordinate at the center of the view)
//StartVec is the position in UV-space were we started to move
//StartPos is the UVPos that was saved when we started dragmoving
//MouseVec is the current UV-coordinate at which the mouse points.

procedure TMainForm.ViewUVMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
begin
DragMoving := True;

GL.UnProjectUV(X, Y, StartVec.x, StartVec.y);
StartPos.x := UVPos.u;
StartPos.y := UVPos.v;
end;
end;

procedure TMainForm.ViewUVMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if DragMoving then
begin
//Unproject mouse coordinates
GL.UnProjectUV(X, Y, MouseVec.x, MouseVec.y);

//Update position of Viewport
UVPos.u := StartPos.x + (StartVec.x - MouseVec.x);
UVPos.v := StartPos.y + (StartVec.y - MouseVec.y);
end;
end;

procedure TMainForm.ViewUVMouvseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then DragMoving := False;
end;

procedure TGLRenderer.UnProjectUV(X, Y: Integer; out U, V: Single);
var
viewport: TGLVectori4;
modelview: TGLMatrixd4;
projection: TGLMatrixd4;
dU, dV, dW: Double;
begin
//Set UV matrices
ViewUV(fUVPosition.u, fUVPosition.v, fUVViewSize);

//Retrieve matrices
glGetDoublev( GL_MODELVIEW_MATRIX, @modelview );
glGetDoublev( GL_PROJECTION_MATRIX, @projection );
glGetIntegerv( GL_VIEWPORT, @viewport );

// In Delphi A Y Value Of 0 Returns An Unknown Value
// I Discovered This While I Was Testing A Crosshair
if( Y = 0 )then Y := 1;

gluUnProject( X, viewport[3]-Y, 0,
modelview, projection, viewport,
@dU, @dV, @dW);

//Convert from Double to Single
U := dU;
V := dV;
end;


It works, but it becomes jerky very quickly. I figure that that is caused by some "feedback" effect. MouseVec depends on the position of the viewport (UVPos), but MouseVec also AFFECTS the position of the viewport. It's like a circle. :o

I'm looking for a better sollution, but i can't think of one. Can someone help me?

Thanks in advance. :)

ize
25-03-2009, 09:19 PM
Hi there. I'm not sure if this is the same thing, but i use a similar method for my apps in GLScene (admittedly a LOT of the hard work is done for me ;)) I only store the screen co-ords though:

Psuedo


var
oldx,oldy : integer; // previous mouse position

onMouseDown:
begin
oldx =mousex;
oldy =mousey;
end;

onMouseMove(X,Y: integer / mouse position passed to procedure):
var
owv,wv: TVector (array[0..3] of single); // old and current world position
begin
owv = ScreenVectorIntersectWithPlaneXZ(oldx,oldy)
wv =ScreenVectorIntersectWithPlaneXZ(X,Y)
camera position = camera position + (vectorsubtract(owv,wv))
oldx =x; oldy = y; <- important otherwise you get acceleration (which is what you might be getting)
end;


Or have i got completely the wrong end of the stick?(it wouldn't be the first time!)

chronozphere
25-03-2009, 10:25 PM
Thanks for your reply. It works now :D

Here's the source:


//StartMousePos is the starting point of the mouse in screen coordinates
//MousePos is the current position of the mouse in screen coordinates
//UVPos is the current UV-position of the viewport center
//StartUVPos is the initial UV-position of the viewport center (when we started dragging).

procedure TMainForm.ViewUVMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
begin
DragMoving := True;
StartMousePos.X := X;
StartMousePos.Y := Y;
StartUVPos.u := UVPos.u;
StartUVPos.v := UVPos.v;
end;
end;

procedure TMainForm.ViewUVMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
uFactor, vFactor: Single;
begin
if DragMoving then
begin
MousePos.X := X;
MousePos.Y := Y;

//Scales displacement-vector from screen to UV-coordinates (Flip Y-axis)
uFactor := UVSize/ViewUV.Width;
vFactor := -(UVSize/ViewUV.Height);

//Transform displacement vector and combine it with the initial viewport position
UVPos.u := StartUVPos.u - (MousePos.x - StartMousePos.x)*uFactor;
UVPos.v := StartUVPos.v - (MousePos.y - StartMousePos.y)*vFactor;
end;
end;

procedure TMainForm.ViewUVMouvseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
begin
DragMoving := False;
MousePos.X := 0;
MousePos.Y := 0;
StartMousePos.X := 0;
StartMousePos.Y := 0;
end;
end;


Instead of using gluUnProject, i figured that it was easier to just transform by hand. If you want to rotate your view, this can be tedious though, but i don't need this. I got rid of the "feedback" effect now. :)