【问题标题】:detect mouse clicks in OpenGL C++在 OpenGL C++ 中检测鼠标点击
【发布时间】:2013-04-19 10:26:15
【问题描述】:

我是 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;
    }
}

这是主要功能:

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

我做错了什么?

编辑 我对代码做了一些更改,但背景图像仍然没有改变。这是新的主要功能:

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

这是我将纹理映射到四边形的显示函数:

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

【问题讨论】:

  • 您的问题是关于 GLUT,而不是 OpenGL。

标签: c++ glut


【解决方案1】:

你的顺序错了。

glutMouseFunc(mouseClicks);

在这里注册鼠标点击时要调用的函数。

if(onMouse == 1) {

你立即检查鼠标是否被点击。在这两行之间的短暂时间里,鼠标不可能被点击,并且glutMainLoop还没有被输入,所以你的程序甚至没有机会监听鼠标事件。


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

【讨论】:

  • 我改变了顺序,现在我在函数 DisplayFunc() 和 KeyboardFunc() 之间有 glutMouseFunc(mouseClicks) 并且在调用 glutMainLoop() 之后我检查 onMouse 是否具有值 1;该程序仍然没有改变图像,但至少现在我没有崩溃
【解决方案2】:

我做错了什么?

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

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

这就是你要做的(在简化的伪代码中)

// 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();
}

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

【讨论】:

    【解决方案3】:

    glutMouseFunc 注册一个回调:在特定事件(这里是鼠标事件)上调用的函数。这些事件由glutMainLoop收集,测试onMouse时尚未调用。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-17
      • 2020-04-18
      • 2021-09-06
      • 2015-08-03
      相关资源
      最近更新 更多