使用 GLUT 和 C 闪烁 2D 纹理

Posted

技术标签:

【中文标题】使用 GLUT 和 C 闪烁 2D 纹理【英文标题】:Flickering 2D Texture using GLUT and C 【发布时间】:2017-05-30 06:15:42 【问题描述】:

我正在尝试使用纯 C 语言制作一个chip8 模拟器。我设置了大部分操作码,所以我只需要在显示器上工作。我决定使用 GLUT 进行显示,因为它看起来很快速设置。主要思想是将chip8精灵显示到2D纹理上。我让它通过一些操作码执行来显示一些数字,但它在闪烁。我正在使用双缓冲,因为从我读到的内容来看,这是确保可以显示某些内容的最佳方法,但我仍然在闪烁。关于可能导致它的任何想法?

这是用于显示的 OpenGL 和 GLUT 的所有代码。

int main(int argc,  char * argv[]) 

//    if(argc < 2)
//        printf("Usage: %s <bin file>\n", argv[0]);
//        exit(0);
//    

    //initialize chip 8
    chip8_Init();
    //load file if exists
    chip8_load("test6.bin");

    //setup graphics
    glutInit(&argc, argv);
    glutInitWindowSize(display_width, display_height);
    glutInitWindowPosition(320, 320);
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
    glutCreateWindow("Chip8 GL");
    setupTexture();
    glutDisplayFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutIdleFunc(renderScene);
    glutKeyboardFunc(chip8_keypad);
    glutKeyboardUpFunc(chip8_keypadUp);

    glutMainLoop();
    return 0;



void setupTexture() 
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);


    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);

    //set texture parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                GL_NEAREST);
    //update texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
             SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
             screenData);


void updateTexture() //display()
    //update pixels
    for (int i = 0; i < SCREEN_HEIGHT; i++) 
        for (int j = 0; j < SCREEN_WIDTH; j++) 
            if(chip8.gfx[(i * SCREEN_WIDTH)+j] == 0)
                screenData[i][j][0] = 0;
                screenData[i][j][1] = 0;
                screenData[i][j][2] = 0;
            
            else
                screenData[i][j][0] = 255;
                screenData[i][j][1] = 255;
                screenData[i][j][2] = 255;
              
        
    
    //update texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
             SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
             screenData);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glBindTexture(GL_TEXTURE_2D, texName);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2d(0.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex2d(display_width, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex2d(display_width, display_height);
    glTexCoord2f(0.0, 1.0); glVertex2d(0.0, display_height);

    glEnd();
    glutSwapBuffers();


void renderScene()
    chip8_emulateCycle();
    if(drawFlag == 1)
    updateTexture();
    drawFlag = 0;
      


void changeSize(int w, int h)
    glClearColor(0.0f, 0.0f, 0.5f, 0.0f);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, w, h, 0);
    glMatrixMode(GL_MODELVIEW);
    glViewport(0, 0, w, h);

    // Resize quad
    display_width = w;
    display_height = h;

编辑:我可能已经想通了。在绘图操作码中,它使用 XOR。所以当第一次绘制命令时,精灵被显示,当再次调用它时,它就会消失,依此类推。

【问题讨论】:

在对纹理进行操作之前不应该调用glBindTexture(GL_TEXTURE_2D, texName); 吗?禁用双缓冲会改变行为吗? 【参考方案1】:

我的opengl很尘土飞扬,但我在你的代码中看到了一些点:

您应该在初始化之前启用GL_TEXTURE_2D

void setupTexture()
 
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);


    /* enable texturing */
    glEnable(GL_TEXTURE_2D);
    /* create texture */
    glGenTextures(1, &texName);
    /* select texture */
    glBindTexture(GL_TEXTURE_2D, texName);

    /* select behavior */
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

    /* ... */


你应该在修改之前选择纹理

void updateTexture() 
    /* update pixels */
    /* ... */

    /*select texture */
    glBindTexture(GL_TEXTURE_2D, texName);

    /*update texture */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
             SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
             screenData);

    /* clear screen */    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* draw texture */
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2d(0.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex2d(display_width, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex2d(display_width, display_height);
    glTexCoord2f(0.0, 1.0); glVertex2d(0.0, display_height);
    glEnd();

    glutSwapBuffers();

此外,您可以使用glGetError()来测试调用函数的结果:

void check_for_error(void)

    GLenum err = glGetError();
    if (GL_NO_ERROR != err)
    
        fprintf("Error %d\n", err);
        exit(EXIT_FAILURE);
    

话说,我不知道chip8.gfx[]里面的数据,可能和你想象的不一样。

【讨论】:

以上是关于使用 GLUT 和 C 闪烁 2D 纹理的主要内容,如果未能解决你的问题,请参考以下文章

从位图图像中读取2D纹理(C ++,OpenGL)

闪烁的金属输出纹理...为啥?

GLUT_DOUBLE和GLUT_SINGLE 用例

cocos2d如何预加载资源?

使用 Glut 和 C 时扭曲的纹理

使用 WM_DRAWITEM 闪烁