Archived

This topic is now archived and is closed to further replies.

Explosive

Mouse coordinates to OpenGL coordinates?

Recommended Posts

How it can be done? I want to move my 3D cube with the mouse,but there is a difference between windows coordinates of the mouse (i draw in a window)and GL coordinates of my cube wich is at the origin of the scene.I use glRenderMode(GL_SELECT),I mean that I can determinate that my mouse is on the cube, and I can grab it,but when I move mouse the cube didn''t move equaly with mouse becouse of the coordinates....What I must done?

Share this post


Link to post
Share on other sites
I use this code to pick 2D objects but I think it may be useful.
It has to be written in the WindowProc.

case WM_MOUSEMOVE:
{
MousePos.x = (int)(((float)LOWORD(lParam))/APP_WIDTH);
MousePos.y = (int)(((float)HIWORD(lParam))/APP_HEIGHT);
}
break;

The max value it gives to mousePos.x and MousePos.y are 1.0
The top left corner of the screen is (0,0).
APP_WIDTH and APP_HEIGHT are the width and height of you app.
This code does not work properly if you resize your window.

BTW, does anyone know how to make it impossible to resize the window?

Share this post


Link to post
Share on other sites
I dont know how it is in API code, I use MFC, but saw that:
void CGLView::OnSize(UINT nType, int cx, int cy)
{
TRACE0("OnSize\r\n") ;
CView::OnSize(nType, cx, cy);

// TODO: Add your message handler code here


if((cx <= 0) || (cy <= 0) ) return ;

CClientDC dc(this) ;
//
//Make Rendering Context Current
//

BOOL bResult = wglMakeCurrent(dc.m_hDC, m_hRC) ;
if(!bResult)
{
TRACE("wglMakeCurrent failed - %d\r\n",
GetLastError()) ;
return ;
}
//
//Seting the world
//
m_gldAspect = (GLdouble) cx/ (GLdouble) cy ;
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
gluPerspective(45.0, m_gldAspect, 0.1, 100000.0) ;
glViewport(0, 0, cx, cy) ;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslated(0.0f, 0.0f, -4.0f);


//No rendering contex will be current
wglMakeCurrent(NULL, NULL) ;

}

Share this post


Link to post
Share on other sites
I'm kinda having the same problem as you. I'm using gluProject to get the model's position in screen coordinates like so:

GLdouble modelMatrix[16] ;
GLdouble projMatrix[16] ;
GLint viewPort[4] ;

glGetDoublev ( GL_MODELVIEW_MATRIX, modelMatrix ) ;
glGetDoublev ( GL_PROJECTION_MATRIX, projMatrix ) ;
glGetIntegerv ( GL_VIEWPORT, viewPort ) ;

gluProject ( sprite_x,
sprite_y, sprite_z ,
modelMatrix, projMatrix, viewPort,
&screen_x, &screen_y, &screen_z ) ;

I'm not exactly sure what screen_z is all about. I guess its to mirror gluUnProject. Anyway, you can just ignore it

Now you've got the model's screen coordinates, I'll leave it up to you to decide if the mouse is over it and if it is clicked or whatever.

The next part is where I've been having trouble. You can you gluUnProject to convert the screen coordinates to your model's coordinate system...

gluUnProject ( (double) mouse_x,
(double) mouse_y, 0.0,
modelMatrix, projMatrix, viewPort,
&x, &y, &z );

Unfortunately this gives coordinates that are pretty mush useless. z will be the camera's z and x and y will be there, not where z=0 which is what you want. I've tried putting different values in where I have 0.0 above, but It didn't really do what I want.

So what you (and I) need is to be able to make a vector from the camera that passes through the x,y,z from gluUnproject above and find out where it intersects the z=0 plane.

I hope this gets you a little further, and if you do find the soution please post it here, since I need the answer too.

Peace.


[edited by - JahToasted on January 17, 2004 2:11:22 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by lazork357
I use this code to pick 2D objects but I think it may be useful.
It has to be written in the WindowProc.

case WM_MOUSEMOVE:
{
MousePos.x = (int)(((float)LOWORD(lParam))/APP_WIDTH);
MousePos.y = (int)(((float)HIWORD(lParam))/APP_HEIGHT);
}
break;



Here is how you change into window coords.

// Get the mouse''s current X, Y position
POINT mousePos;
GetCursorPos(&mousePos);
ScreenToClient(g_hWnd, &mousePos);

quote:

BTW, does anyone know how to make it impossible to resize the window?


Yes. To do this it''s how you initially create your window. This post is going to be messy but.


///////////////////////////////// CREATE WIN32 WINDOW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

///// This function creates a window, then maps calls to winproc

/////

///////////////////////////////// CREATE WIN32 WINDOW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


HWND CreateWin32Window(LPSTR strWindowName, int width, int height, DWORD dwStyle, bool bFullScreen, HINSTANCE hInstance)
{
ShowCursor(TRUE); // Show the mouse


HWND hWnd;
char class_name[] = "72Hours";

if(!bFullScreen)
{
WNDCLASSEX wndclassex;
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = WinProc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = hInstance;
wndclassex.hIcon = NULL;
wndclassex.hCursor = NULL;
wndclassex.hCursor = (HCURSOR)LoadImage(hInstance, MAKEINTRESOURCE(IDC_POINTER),
IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); // Window sets shape of mouse

wndclassex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclassex.lpszMenuName = NULL;
wndclassex.lpszClassName = class_name;
wndclassex.hIconSm = NULL;

//Support my window without the min/max stuff

RegisterClassEx(&wndclassex);

hWnd = CreateWindowEx(WS_EX_APPWINDOW, // This is a flag that can give our window different properties

class_name,
strWindowName,
WS_OVERLAPPED | WS_SYSMENU, // Window won''t be resizable

0,
0,
width,
height,
NULL,
NULL,
hInstance,
NULL);
}

if(!hWnd)
{
UnregisterClass(class_name, hInstance);
return NULL;
}

ShowWindow(hWnd, SW_SHOWNORMAL); // Show the window

UpdateWindow(hWnd); // Draw the window


SetFocus(hWnd); // Sets Keyboard Focus To The Window


return hWnd;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Does anybody know a place where I can find an example/demo in C++ to move objects with the mouse? I''ve searched a long time but I wasn''t able to find one.

Fanny

Share this post


Link to post
Share on other sites
Since I get mouse input with direct X just multiply the mickey value by some arbitary number 0.001 works nice and translate, or rotate or do whatever with it.

If you want to place an object in an opengl window based on the cursor position then get the cursor position, relative to the client part of the window then do

x=x/Width*2-1
y=y/Height*2-1

And then translate your object, assuming of course that your object is centered on zero.

[edited by - RamboBones on February 29, 2004 10:53:04 PM]

Share this post


Link to post
Share on other sites
Hey Explosive.

You can use gluUnProject to accomplish this.

I have some Delphi source code on my site showing how to do this.

gluUnProject

I seem to remember there being a c++ tutorial on NeHe's site about this also.



[edited by - McCLaw on March 1, 2004 6:23:54 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I have found a demo "smooth.zip" on http://www.opengl.org/resources/code/basics/more_samples/ .
It is written in c, and I was able to run it with Visual C++.
It uses the gluUnProject Feature.

Fanny

Share this post


Link to post
Share on other sites
i am having the same type of problems, although the code on this thread has not helped. i am drawing a QUAD onto the screen using glVertex2f calls. 4 of them to make a rectangle against the screen. well i want to be able to check when the mouse pointer is over this rectangle i.e. or any portion of it.

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_QUADS);
glColor3f(0,1.0, 1.0);
glVertex2i(0, 0);
glColor3f(0,1.0,1.0);
glVertex2i(0, -1);
glColor3f(0,0, 1);
glVertex2i(5, -1);
glColor3f(0, 0, 1);
glVertex2i(5, 0);
glEnd();

so i would like to know when the mouse pointer falls within the boundaries of this QUAD. this of course involves converting the screen coordinates to the the 2D windows coordinates?? please write if you have some insight, ive been racking my brain trying to get this to work.

Share this post


Link to post
Share on other sites
Back when I designing a space RTS game in 3d I ran into this problem, and solved it with peoples help.

I''ll drag out that old source in a bit but suffice it to say that this is how I remember it being done: (I might be wrong. . i''ll double check in a lil bit)

The entire scene is redrawn into another back buffer and instead of drawing a texture onto the polygon/quad, I drew a single colored polygon with the color being the index of the object.

Say we had ships 1, 2 and 3. There was a function in GL to tell you the RGB value of a pixel on that back buffer, and ship 1 was painted the value of 1,0,0.

I might not be right, I think in fact I may have used gluUnproject and I''ll dig that old CD out right now to straighten this out.

Share this post


Link to post
Share on other sites
Here's the code. Apparently, I did use gluProject. Unfortunately, I have just about completely forgot how I did it. It was about 3 years go. This code works, though, as I was just testing the demo out.


void CheckClick()
{

// CHECK SELETION


double modelMatrix[16];
double projMatrix[16];
GLint viewport[4];
glLoadIdentity();

RenderCamera();
double sx1,sy1,sz1;
double sx,sy,sz;
bool renderhit = false;
//int selship;


glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
glGetIntegerv(GL_VIEWPORT,viewport);
// clear all selected



for (int curship = 0; curship < numships; curship++)
{
sx = craft[curship].x;
sy = craft[curship].y;
sz = craft[curship].z;
gluProject(sx,sy,sz, modelMatrix, projMatrix, viewport, &sx1, &sy1, &sz1);
sy1=(480-sy1);


// compare sh and mouse to see if selected

if (mousex>sx1-90)
{
if(mousex<sx1+90)
{
if(mousey>sy1-90)
{
if(mousey<sy1+90)
{
for (int cship = 0; cship<numships; cship++)
{
selship[cship]=false;
}
renderhit=true;
selship[curship]=true;
Mcamera.target=curship;

Mcamera.ctargetstep=1;

Mcamera.cx=(ship[Mcamera.target].x-Mcamera.x)/10;
Mcamera.cy=(ship[Mcamera.target].y-Mcamera.y)/10;
Mcamera.cz=(ship[Mcamera.target].z-Mcamera.z)/10;

}
}
}
}


}

if (mouseclk & MK_LBUTTON)
{
if (renderhit)
{
sprintf(str3, "x: %f y: %f ship#: %i", mousex, mousey, selship);
sprintf(str4, "ship x: %f y: %f z: %f", sx1, sy1, sz1);
}
if (!renderhit)
{
sprintf(str3, "");
sprintf(str4, "
");
}
}
}



Actually, after taking a second look, it looks as though the routine takes the current matrixes, uses gluProject to figure out the current 2d screen coordinate for the given 3d coordinate from the ship array. From that, it's easy enough to compare the coordinates with the mouse coordinates which should be known.

I think i might have cannibalized some code from a NEHE tutorial or something to derive the mouse screen coords.

Ok, I've also dragged out that subroutine out of my code to make sure you have everything. I'm pretty sure this is out of a NEHE tut. The WndProc routine is probably actually in your program, actually. Just add the code to store the mouse location in it.


LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window

UINT uMsg, // Message For This Window

WPARAM wParam, // Additional Message Information

LPARAM lParam) // Additional Message Information

{
switch (uMsg) // Check For Windows Messages

{
case WM_ACTIVATE: // Watch For Window Activate Message

{
if (!HIWORD(wParam)) // Check Minimization State

{
active=TRUE; // Program Is Active

}
else
{
active=FALSE; // Program Is No Longer Active

}

return 0; // Return To The Message Loop

}

case WM_SYSCOMMAND: // Intercept System Commands

{
switch (wParam) // Check System Calls

{
case SC_SCREENSAVE: // Screensaver Trying To Start?

case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?

return 0; // Prevent From Happening

}
break; // Exit

}

case WM_CLOSE: // Did We Receive A Close Message?

{
PostQuitMessage(0); // Send A Quit Message

return 0; // Jump Back

}

case WM_KEYDOWN: // Is A Key Being Held Down?

{
keys[wParam] = TRUE; // If So, Mark It As TRUE

console.keys[wParam] = TRUE;
//if (console.keys['M'])

// sprintf(console.c1, "key pressed");

return 0; // Jump Back

}
//console.CheckKeys();

//sprintf(console.c1, "lkjsd lksdf lksdlkflk");

case WM_KEYUP: // Has A Key Been Released?

{
keys[wParam] = FALSE; // If So, Mark It As FALSE

console.keys[wParam] = FALSE;
return 0; // Jump Back

}

case WM_SIZE: // Resize The OpenGL Window

{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height

return 0; // Jump Back

}
case WM_MOUSEMOVE:
{
// GetMouseMovePoints(sizeof(zazou), zazou, 0,1,GMMP_USE_DISPLAY_POINTS);

zazou.x=LOWORD(lParam);
zazou.y=HIWORD(lParam);

mousex=zazou.x;
mousey=zazou.y;

mx=zazou.x-340;
my=-(zazou.y)+240;
mouseclk=wParam;


}
case WM_RBUTTONDOWN:
{
RmouseBut=TRUE;
}


};

// Pass All Unhandled Messages To DefWindowProc

return DefWindowProc(hWnd,uMsg,wParam,lParam);
}


hope this helps, and hope it actually works and I posted it right. This code has been pulled right out of the source code for a working demo. Yeah, I know the code is messy.

[edited by - Crunchdown on March 1, 2004 11:43:08 PM]

Share this post


Link to post
Share on other sites