0
votes

I'm trying my hand at making a chip8 emulator using just plain C. I got most of the opcodes set so I just need to work on the display. I decided on using GLUT for the display since it appeared quick setup. The main idea is to display the chip8 sprites onto the 2D texture. I got it to display some digits though some opcode execution but it's flickering. I'm using double buffering since from what I read it's the best way to make sure something is ready to be displayed but I'm still getting flickering. Any ideas on what can cause it?

Here's all the code for OpenGL and GLUT for the display.

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

Edit: I might have figured it out. In the draw opcode, it uses XOR. So when the draw command for the first time the sprite is displayed and when called again it disappears and so on so forth.

1
Shouldn't you call glBindTexture(GL_TEXTURE_2D, texName); before acting on the texture? Does disabling double buffering change the behavior?Mathieu

1 Answers

0
votes

My opengl is very dusty, but I saw some points in your code:

You should enable GL_TEXTURE_2D before initialize it:

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

    /* ... */

}

You should select the texture before modifying it

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

Moreover, you may test for the result of called functions, by using glGetError():

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

Said that, I don't know the data inside chip8.gfx[], may be they are not as you expect.