Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

detect mouse clicks in OpenGL C++

Tags:

c++

glut

I am a beginner at OpenGL and I am trying to create a game in which as background I have a raw image. When the game starts I display that image and I want to be able to click on it and to display another image afterwards. I tried using the function glutMouseFunc but when I try to run the program I receive a message which says that the program stopped working. Here are some parts of my code: I have a global variable onMouse; if I click the mouse button the variable takes the value 1 and if it has the value 1 I try to load the second image.

int onMouse;
void mouseClicks(int button, int state, int x, int y) {
    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
        onMouse = 1;
    }
}

And this is the main function:

//load first texture
texture = LoadTextureRAW( "2 Lock screen.raw", TRUE );
glutMouseFunc(mouseClicks);
if(onMouse == 1){
    //load second texture
    texture = LoadTextureRAW( "in_game.raw", TRUE );
}

What am I doing wrong?

EDIT I have made some changes to the code, but the background image still doesn't change. Here is the new main function:

glutCreateWindow("Game");
texture = LoadTextureRAW( "2 Lock screen.raw", 1 );
glutDisplayFunc(display);

glutMouseFunc(mouseClicks);
glutKeyboardFunc(key);

glutMainLoop();

if(onMouse == 1){
        texture = LoadTextureRAW( "in_game.raw", 2 );
        glutDisplayFunc(display);
}

And this is the display function in which I map the texture to a quad:

glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT );

// setup texture mapping
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, texture );

glPushMatrix();
glBegin( GL_QUADS );
glTexCoord2d(1.0,0.0); glVertex3d(1.0,1.0, 1.0);
glTexCoord2d(0.0,0.0); glVertex3d(-1.0,1.0,1.0);
glTexCoord2d(0.0,1.0); glVertex3d(-1.0,-1.0, -1.0);
glTexCoord2d(1.0,1.0); glVertex3d(1.0,-1.0, 1.0);
glEnd();
glPopMatrix();
glutSwapBuffers();

// free the texture
FreeTexture( texture );
like image 795
user1956185 Avatar asked Apr 19 '13 10:04

user1956185


3 Answers

You have the order wrong.

glutMouseFunc(mouseClicks);

Here you register the function to be called when the mouse is clicked.

if(onMouse == 1) {

You immediately check if the mouse had been clicked. It's impossible for the mouse to have been clicked in the brief period between these two lines, and glutMainLoop hasn't been entered yet so your program didn't even have a chance to listen for mouse events.


As for the crash, I can't help you debug it with just the code you have provided. Please try a debugger and find which line causes the crash.

like image 164
Kos Avatar answered Nov 03 '22 18:11

Kos


What am I doing wrong?

You're expecting glutMouseFunc to wait for a mouse click. This is not how GLUT works (GLUT is not part of OpenGL BTW). Another callback to be registered is the drawing function (usually called display in GLUT based programs).

Once you enter the GLUT main loop (glutMainLoop() call) user events are processed and if a redisplay is requested the display function is called.

So here's what you do (in simplified pseudocode)

// Define bitmasks for mouse status, we assume mice have less than 17 buttons
#define MB_LEFT   0
#define MB_MIDDLE 1
#define MB_RIGHT  2
#define LMB_PRESSED (1<<0)
#define MMB_PRESSED (1<<1)
#define RMB_PRESSED (1<<2)
#define LMB_CLICKED (1<<16)
#define MMB_CLICKED (1<<17)
#define RMB_CLICKED (1<<18)
#define MB_PRESSED(state, button) (1<<(button))
#define MB_CLICKED(state, button) (1<<((button)+16)))
#define MB_MASK_PRESSED 0x0000ffffL
#define MB_MASK_CLICKED 0xffff0000L

uint32_t mouse_status = 0;

void onMouseButton(int button, int state, int x, int y)
{
    int b;
    switch(button) {
    case GLUT_LEFT_BUTTON:   b=MB_LEFT;   break;
    case GLUT_MIDDLE_BUTTON: b=MB_MIDDLE; break;
    case GLUT_RIGHT_BUTTON:  b=MB_RIGHT;  break;
    }

    if(mouse_status & MB_PRESSED(b) && GLUT_UP == state) {
        mouse_status |= MB_CLICKED(b);
    }
    if( !(mouse_status & MB_PRESSED(b)) && GLUT_DOWN == state) {
        mouse_status = (mouse_status & ~(0L | MB_CLICKED(b))) | MB_PRESSED(b);
    }

    glutPostRedisplay();
}

void display(void)
{
    if(mouse_status & MB_CLICKED(MB_LEFT)) {
        /* do something */
        …

        /* clear the click flag */
        mouse_status &= ~MB_MASK_CLICKED;
    }
}

int main(…)
{
    …
    glutCreateWindow(…);
    glutDisplayFunc(display);
    glutMouseFunc(onMouseButton);

    glutMainLoop();
}

You can of course use any other kind of structure you like to pass the mouse button status between program parts. I prefer bitmasks for such. Other people may prefer arrays (personally I don't like arrays for tasks like this, because they're not as easy to look at in a debugger than a simple bitfield).

like image 40
datenwolf Avatar answered Nov 03 '22 17:11

datenwolf


glutMouseFunc registers a callback: a function to be called on specific events (here mouse events). These events are collected by glutMainLoop, which has not been called yet when you test onMouse.

Another thing, though I cannot tell for sure from the small code excerpt you provide, is that you'd better load the assets from the start of the programme, rather than wait for a user event to do it. Load them first, and simply change texture to whichever id correspond to the texture you wish to display then.

like image 26
didierc Avatar answered Nov 03 '22 17:11

didierc