7

我是 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 );
4

3 回答 3

8

你的顺序错了。

glutMouseFunc(mouseClicks);

在这里,您注册了单击鼠标时要调用的函数。

if(onMouse == 1) {

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


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

于 2013-04-19T10:31:55.710 回答
6

我究竟做错了什么?

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

一旦进入 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();
}

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

于 2013-04-19T10:49:46.790 回答
1

glutMouseFunc注册一个回调:在特定事件(这里是鼠标事件)上调用的函数。这些事件是被收集的glutMainLoop,在你测试的时候还没有被调用onMouse

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

于 2013-04-19T11:06:51.727 回答