在 OpenGL C++ 中检测鼠标点击

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16102503/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:04:21  来源:igfitidea点击:

detect mouse clicks in OpenGL C++

c++glut

提问by user1956185

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 glutMouseFuncbut 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.

我是 OpenGL 的初学者,我正在尝试创建一个游戏,其中我有一个原始图像作为背景。当游戏开始时,我会显示该图像,并且我希望能够单击它并在之后显示另一张图像。我尝试使用该功能,glutMouseFunc但是当我尝试运行该程序时,我收到一条消息,指出该程序停止工作。这是我的代码的一些部分: 我有一个全局变量 onMouse;如果我单击鼠标按钮,该变量的值为 1,如果它的值为 1,我将尝试加载第二张图像。

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?

我究竟做错了什么?

EDITI 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 );

回答by Kos

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 glutMainLoophasn't been entered yet so your program didn't even have a chance to listen for mouse events.

您立即检查鼠标是否已被单击。鼠标不可能在这两行之间的短暂时间内被单击,并且glutMainLoop尚未输入,因此您的程序甚至没有机会侦听鼠标事件。



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.

至于崩溃,我无法仅用您提供的代码来帮助您调试。请尝试调试器并找出导致崩溃的行。

回答by datenwolf

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 displayin GLUT based programs).

您期望 glutMouseFunc 等待鼠标单击。这不是 GLUT 的工作方式(GLUT 不是 OpenGL BTW 的一部分)。另一个要注册的回调是绘图函数(通常display在基于 GLUT 的程序中调用)。

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

一旦您进入 GLUT 主循环(glutMainLoop()调用),就会处理用户事件,如果请求重新显示,则调用显示函数。

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).

您当然可以使用您喜欢的任何其他类型的结构在程序部分之间传递鼠标按钮状态。我更喜欢这样的位掩码。其他人可能更喜欢数组(我个人不喜欢这样的任务的数组,因为在调试器中它们不像简单的位域那样容易查看)。

回答by didierc

glutMouseFuncregisters 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.

glutMouseFunc注册回调:在特定事件(此处为鼠标事件)上调用的函数。这些事件由 收集glutMainLoop,在您测试时尚未调用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 textureto whichever id correspond to the texture you wish to display then.

另一件事,虽然我不能从你提供的小代码摘录中确定,你最好从程序开始加载资产,而不是等待用户事件来做。首先加载它们,然后简单地更改texture为与您希望显示的纹理对应的任何 id。