Sign in to follow this  
adam_o

[SDL] Translating mouse coordinates in SDL into OpenGL space

Recommended Posts

I know I've seen the code for this somewhere, but I can't remember, so I'm calling upon your superior memories to help me figure this out: when SDL outputs coordinates, it outputs them in 2D, "screen-level" coordinates. Now from that I would like to figure out how to determine what the mouse would have "touched" in a 2D or 3D OpenGL environment. Is there something that would figure this out for me somehow? All help is appreciated and thanks in advance. adam_o

Share this post


Link to post
Share on other sites
It sounds like you're looking for gluUnProject. It takes screen-space coordinates and returns world-space coordinates, based on the passed viewport and matrices. For help on determining what the user is trying to click on, google around for "opengl mouse picking" (the first result is one simple and common way to do it, though faster methods do exist).

Share this post


Link to post
Share on other sites
Quote:
Original post by jouley
It sounds like you're looking for gluUnProject. It takes screen-space coordinates and returns world-space coordinates, based on the passed viewport and matrices. For help on determining what the user is trying to click on, google around for "opengl mouse picking" (the first result is one simple and common way to do it, though faster methods do exist).


Ok, thank you. I'll try to work with that, and if I have any more problems, I'll post again.

Share this post


Link to post
Share on other sites
I finally got around to trying out gluUnProject(), but my program crashed and the data was wrong. So I tried gluProject() (because I figured it might be the other way around; I'm using mouse coordinates to find what the mouse clicked on) and it gave me weird numbers, but I got the numbers. The problem is, with both versions of Project(), my program crashes, and if I simply comment the Project() code, the program works fine. Here's my code:

int x_loc = event.button.x;
int y_loc = event.button.y;
fileout << "(" << x_loc << "," << y_loc << ")" << endl << flush;
GLdouble mv_matrix;
GLdouble prj_matrix;
GLint vp;
GLdouble xdest, ydest, zdest;
glGetDoublev(GL_MODELVIEW, &mv_matrix);
glGetDoublev(GL_PROJECTION, &prj_matrix);
glGetIntegerv(GL_VIEWPORT, &vp);
gluProject(x_loc, y_loc, 0, &mv_matrix, &prj_matrix, &vp,
&xdest, &ydest, &zdest);
fileout << "(" << xdest << ", " << ydest << ", "
<< zdest << ")" << endl << flush;


And here's what I got:
(431,82)
(504.471, 380.626, -0.108788)
(14,37)
(504.471, 383.39, -0.10159)
(433,329)
(504.471, 378.919, -0.113231)
(222,153)
(504.471, 379.571, -0.111534)
(74,332)
(504.471, 378.914, -0.113244)
(these are five random points on the screen, SDL coordinate pairs first and OpenGL triples second)

So am I using this code wrong? Why is it hanging up? Is it gluProject() or gluUnproject()?

EDIT: I'd like to add that the program crashes iff I click the mouse button (which activates glu*Project()). Otherwise, it runs just fine. Another weird thing to note is that it crashes on exit, not when I click the button.

[Edited by - adam_o on January 21, 2008 9:57:14 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by adam_o
I finally got around to trying out gluUnProject()...
Which is the function you're looking for. gluProject is used to turn world space coordinates into screen space
Quote:
...but my program crashed and the data was wrong.
Taking a look at your code, I've commented some trouble spots:
int x_loc = event.button.x;
int y_loc = event.button.y;
fileout << "(" << x_loc << "," << y_loc << ")" << endl << flush;

// you create one GLdouble here, but glGetDoublev will try to fill the
// pointed-at space with 16 doubles (each element of a 4x4 matrix).
GLdouble mv_matrix; // should be: GLdouble mv_matrix[16];
GLdouble prj_matrix; // likewise
GLint vp; // here, the viewport will only hold 4 values
GLdouble xdest, ydest, zdest;
glGetDoublev(GL_MODELVIEW, &mv_matrix);
glGetDoublev(GL_PROJECTION, &prj_matrix);
glGetIntegerv(GL_VIEWPORT, &vp);
gluProject(x_loc, y_loc, 0, &mv_matrix, &prj_matrix, &vp,
&xdest, &ydest, &zdest);
fileout << "(" << xdest << ", " << ydest << ", "
<< zdest << ")" << endl << flush;


Quote:
So am I using this code wrong? Why is it hanging up? Is it gluProject() or gluUnproject()?
To summarize: Yep. Because it's trying to write to memory space it doesn't own. gluUnProject( ).

Quote:
EDIT: I'd like to add that the program crashes iff I click the mouse button (which activates glu*Project()). Otherwise, it runs just fine. Another weird thing to note is that it crashes on exit, not when I click the button.
The crash only happens iff you click because nothing is going wrong otherwise, meaning the problem is definitely within the given code. The crash happening on exit is just how this particular bug has chosen to manifest itself. You're lucky it didn't turn your oven on for you. The garbage numbers you were getting is likely because the values from one matrix were overwriting those from the others, since the allocated space was contiguous. You can learn more about the glGet* functions here, including what their parameters/return values are.

Best of luck!
-jouley

Share this post


Link to post
Share on other sites
I just tried what you suggested, but got these errors:

92: error: cannot convert 'GLdouble (*)[4][4]' to 'GLdouble*' for argument '2' to 'void glGetDoublev(GLenum, GLdouble*)'
(etc)

So it says that the second argument of glGetDoublev is not a 4x4 array.

EDIT: An interesting thing that I found is that under the link you gave me (*Mac shudders) is that the enum is GL_MODELVIEW_MATRIX, not GL_MODELVIEW. I'll test this out and edit again with results.

Share this post


Link to post
Share on other sites
Something that warranted a new post... when I changed the code to this:
int x_loc = event.button.x;
int y_loc = event.button.y;
fileout << "(" << x_loc << "," << y_loc << ")" << endl << flush;
GLdouble mv_matrix;
GLdouble prj_matrix;
GLint vp;
GLdouble xdest, ydest, zdest;
glGetDoublev(GL_MODELVIEW_MATRIX, &mv_matrix);
glGetDoublev(GL_PROJECTION_MATRIX, &prj_matrix);
glGetIntegerv(GL_VIEWPORT, &vp);
gluProject(x_loc, y_loc, 0, &mv_matrix, &prj_matrix, &vp,
&xdest, &ydest, &zdest);
fileout << "(" << xdest << ", " << ydest << ", "
<< zdest << ")" << endl << flush;

The debugger came up as usual, but it did shut itself off after printing this:
Loading program into debugger…
GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Tue Oct 2 04:11:19 UTC 2007)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "powerpc-apple-darwin".Program loaded.
sharedlibrary apply-load-rules all
Attaching to program: `/Users/atg/Desktop/Projects/Xcode Projects/Release/Tetris_020.app/Contents/MacOS/Tetris_020', process 864.
gdb stack crawl at point of internal error:
[ 0 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (align_down+0x0) [0x11d4fc]
[ 1 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (frame_register+0x98) [0x123c6c]
[ 2 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (frame_register_read+0x2c) [0x123d78]
[ 3 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (do_frame_register_read+0x10) [0x123dc0]
[ 4 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (regcache_save+0xd8) [0x2b900]
[ 5 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (frame_save_as_regcache+0x4c) [0x122b88]
[ 6 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (frame_pop+0x20) [0x124e64]
[ 7 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (hand_function_call+0xde4) [0x5e38c]
[ 8 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (allocate_space_in_inferior_malloc+0xc8) [0x38e80]
[ 9 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (macosx_allocate_space_in_inferior_helper+0x24) [0x18265c]
[ 10 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (catch_exceptions_with_msg+0x5c) [0x76568]
[ 11 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (macosx_allocate_space_in_inferior+0x88) [0x182704]
[ 12 ] /Developer/usr/libexec/gdb/gdb-powerpc-apple-darwin (value_string+0x15c) [0x3e1a8]
/SourceCache/gdb/gdb-768/src/gdb/frame.c:661: internal-error: frame_register: Assertion `frame != NULL && frame->next != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.

The Debugger Debugger is attaching to process(gdb)
Now I know that the 0-12 list is something very important, but I have no clue what, as I do not know how to use this newer version of XCode. If you know what it means, that would be helpful, but I think I may have to go to the Mac mailing lists for this.

Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot
OpenGL uses a 16 element one-dimensional array for its matrices.


I understand this. I have understood this from my first day programming OpenGL. Your brief "helpfulness" didn't do anything. I suggest if you really want to help, that you go over this topic and see what I mean. Otherwise, waste your time in the Lounge.

Share this post


Link to post
Share on other sites
Quote:
Original post by adam_o
Quote:
Original post by smart_idiot
OpenGL uses a 16 element one-dimensional array for its matrices.


I understand this. I have understood this from my first day programming OpenGL. Your brief "helpfulness" didn't do anything. I suggest if you really want to help, that you go over this topic and see what I mean. Otherwise, waste your time in the Lounge.


The hardest things to learn are the things you think you already know.


double modelMatrix[16]; // <-- A one dimensional array, with 16 elements.
double projMatrix[16];
int viewport[4];

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

gluUnProject(mouse_x, viewport[3]-mouse_y, mouse_depth, modelMatrix, projMatrix, viewport, &position_x, &position_y, &position_z);




The value for mouse_depth is a tricky value to get, how far into the screen is the mouse? You can either use gluProject on a known point, and use its depth, making the mouse as far into the screen as that point is, or you can read the data from the depth buffer, and use the point under the mouse, in which case it will follow the surface of the geometry being rendered.

Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot

*** Source Snippet Removed ***

The value for mouse_depth is a tricky value to get, how far into the screen is the mouse? You can either use gluProject on a known point, and use its depth, making the mouse as far into the screen as that point is, or you can read the data from the depth buffer, and use the point under the mouse, in which case it will follow the surface of the geometry being rendered.


Ok, here's some nice help. A few questions though:
• Is your "mouse_x" and "mouse_y" equivalent to my x_loc and y_loc?
• Correct me if I'm wrong, but isn't the point of this to take the 2D coordinates of the mouse and "UnProject" them so I can know where the mouse is clicking? The mouse doesn't have a 3rd dimension in SDL, so it only gives me 2 dimensions, so where does that put "mouse_depth"?

Also, I still get the "cannot convert..." errors with the matrix arrays. The computer's telling me that the second argument of glGetDoublev() is ONE double, not a double array.

Share this post


Link to post
Share on other sites
Is your "mouse_x" and "mouse_y" equivalent to my x_loc and y_loc?
Most likely.

Correct me if I'm wrong, but isn't the point of this to take the 2D coordinates of the mouse and "UnProject" them so I can know where the mouse is clicking? The mouse doesn't have a 3rd dimension in SDL, so it only gives me 2 dimensions, so where does that put "mouse_depth"?

You'll need to specify the depth. Are you pointing to the surface of the camera lens, some point a million parsecs away, or somewhere in between?

Assuming the point of this is to interact with some object on the screen, use gluProject on that object's center, and then use gluUnProject using your mouse position and the depth value you got from the object, and then the mouse will effectively be floating on an invisible plane intersecting the object you want to interact with.

Quote:

The value for mouse_depth is a tricky value to get, how far into the screen is the mouse? You can either use gluProject on a known point, and use its depth, making the mouse as far into the screen as that point is, or you can read the data from the depth buffer, and use the point under the mouse, in which case it will follow the surface of the geometry being rendered.


Also, I still get the "cannot convert..." errors with the matrix arrays. The computer's telling me that the second argument of glGetDoublev() is ONE double, not a double array.

You're probably trying to pass the address of the array and not the array itself.

Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot
You'll need to specify the depth. Are you pointing to the surface of the camera lens, some point a million parsecs away, or somewhere in between?

Assuming the point of this is to interact with some object on the screen, use gluProject on that object's center, and then use gluUnProject using your mouse position and the depth value you got from the object, and then the mouse will effectively be floating on an invisible plane intersecting the object you want to interact with.

Ok, so what if I use gluOrtho2D? Then it doesn't have a z axis, correct?
Quote:
Original post by smart_idiot
You're probably trying to pass the address of the array and not the array itself.

... and for some reason this made more sense than anything else, no offense to you, it just wasn't clicking.

Share this post


Link to post
Share on other sites
While you have a z-axis in orthogonal projection mode, you won't have any distortion with regards to perspective, so it doesn't matter what Z depth an object is actually at. So in this case, you should be able to pick an arbitrary value for the mouse depth.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this