CHIP Emulator(3)——OK!

在完成了CHIP8的核心實現後,剩下的事情就是完成畫面和輸入。爲了邏輯區分不干擾,這一部分代碼放在main.c函數中實現。其實這部分因爲有關GLUT的應用,我也不是太瞭解,因爲我的重點不是放在這上面,所以所做的就是把參考源碼依瓢畫葫蘆,最終實現了CHIP8.

關於GLUT,首先你要進行安裝,這裏給出Linux下的安裝方式GLUT安裝

GLUT教程,網上找到了兩個,一個是翻譯了一部分的,一個原教程。看了以後,main.c中的代碼就很容易理解了。對GLUT有興趣的可以參考下面教程進行深入瞭解。

教程1:翻譯教程
教程2:原教程(英文)

main.c代碼:

#include <stdio.h>
#include <GL/glut.h>
#include "mychip8.h"

// Display size
#define SCREEN_WIDTH 64
#define SCREEN_HEIGHT 32

int modifier = 10;

// Window size
// int display_width = SCREEN_WIDTH * modifier;
// int display_height = SCREEN_HEIGHT * modifier;

 int display_width = 640;
 int display_height = 320;

void display();
void reshape_window(GLsizei w, GLsizei h);
void keyboardUp(unsigned char key, int x, int y);
void keyboardDown(unsigned char key, int x, int y);

// Use new drawing method
#define DRAWWITHTEXTURE
//typedef unsigned __int8 u8;

unsigned char screenData[SCREEN_HEIGHT][SCREEN_WIDTH][3]; 
void setupTexture();

int main(int argc, char **argv) 
{       
    if(argc < 2)
    {
        printf("Usage: myChip8.exe chip8application\n\n");
        return 1;
    }

    // Load game
    if(!LoadApp(argv[1]))       
        return 1;

    // Setup OpenGLabclixu123

    glutInit(&argc, argv);          
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    glutInitWindowSize(display_width, display_height);
    glutInitWindowPosition(320, 320);
    glutCreateWindow("myChip8 by Laurence Muller");

    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc(reshape_window);        
    glutKeyboardFunc(keyboardDown);
    glutKeyboardUpFunc(keyboardUp); 

#ifdef DRAWWITHTEXTURE
    setupTexture();         
#endif  

    glutMainLoop(); 

    return 0;
}

// Setup Texture
void setupTexture()
{
    int x, y;
    // Clear screen
    for(y = 0; y < SCREEN_HEIGHT; ++y)      
        for(x = 0; x < SCREEN_WIDTH; ++x)
            screenData[y][x][0] = screenData[y][x][1] = screenData[y][x][2] = 0;

    // Create a texture 
    glTexImage2D(GL_TEXTURE_2D, 0, 3, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)screenData);

    // Set up the texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

    // Enable textures
    glEnable(GL_TEXTURE_2D);
}

void updateTexture()
{   
    int x, y;
    // Update pixels
    for( y = 0; y < 32; ++y)        
        for( x = 0; x < 64; ++x)
            if(Gfx[(y * 64) + x] == 0)
                screenData[y][x][0] = screenData[y][x][1] = screenData[y][x][2] = 0;    // Disabled
            else 
                screenData[y][x][0] = screenData[y][x][1] = screenData[y][x][2] = 255;  // Enabled

    // Update Texture
    glTexSubImage2D(GL_TEXTURE_2D, 0 ,0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)screenData);

    glBegin( GL_QUADS );
        glTexCoord2d(0.0, 0.0);     glVertex2d(0.0,           0.0);
        glTexCoord2d(1.0, 0.0);     glVertex2d(display_width, 0.0);
        glTexCoord2d(1.0, 1.0);     glVertex2d(display_width, display_height);
        glTexCoord2d(0.0, 1.0);     glVertex2d(0.0,           display_height);
    glEnd();
}

// Old gfx code
void drawPixel(int x, int y)
{
    glBegin(GL_QUADS);
        glVertex3f((x * modifier) + 0.0f,     (y * modifier) + 0.0f,     0.0f);
        glVertex3f((x * modifier) + 0.0f,     (y * modifier) + modifier, 0.0f);
        glVertex3f((x * modifier) + modifier, (y * modifier) + modifier, 0.0f);
        glVertex3f((x * modifier) + modifier, (y * modifier) + 0.0f,     0.0f);
    glEnd();
}

void updateQuads()
{
    int x, y;
    // Draw
    for( y = 0; y < 32; ++y)        
        for( x = 0; x < 64; ++x)
        {
            if(Gfx[(y*64) + x] == 0) 
                glColor3f(0.0f,0.0f,0.0f);          
            else 
                glColor3f(1.0f,1.0f,1.0f);

            drawPixel(x, y);
        }
}

void display()
{
    HandleOpcode();

    if(DrawFlag)
    {
        // Clear framebuffer
        glClear(GL_COLOR_BUFFER_BIT);

#ifdef DRAWWITHTEXTURE
        updateTexture();
#else
        updateQuads();      
#endif          

        // Swap buffers!
        glutSwapBuffers();    

        // Processed frame
        DrawFlag = 0;
    }
}

void reshape_window(GLsizei w, GLsizei 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;
}

void keyboardDown(unsigned char key, int x, int y)
{
    if(key == 27)    // esc
        ;//exit(0);

    if(key == '1')      Keyboard[0x1] = 1;
    else if(key == '2') Keyboard[0x2] = 1;
    else if(key == '3') Keyboard[0x3] = 1;
    else if(key == '4') Keyboard[0xC] = 1;

    else if(key == 'q') Keyboard[0x4] = 1;
    else if(key == 'w') Keyboard[0x5] = 1;
    else if(key == 'e') Keyboard[0x6] = 1;
    else if(key == 'r') Keyboard[0xD] = 1;

    else if(key == 'a') Keyboard[0x7] = 1;
    else if(key == 's') Keyboard[0x8] = 1;
    else if(key == 'd') Keyboard[0x9] = 1;
    else if(key == 'f') Keyboard[0xE] = 1;

    else if(key == 'z') Keyboard[0xA] = 1;
    else if(key == 'x') Keyboard[0x0] = 1;
    else if(key == 'c') Keyboard[0xB] = 1;
    else if(key == 'v') Keyboard[0xF] = 1;

    //printf("Press key %c\n", key);
}

void keyboardUp(unsigned char key, int x, int y)
{
    if(key == '1')      Keyboard[0x1] = 0;
    else if(key == '2') Keyboard[0x2] = 0;
    else if(key == '3') Keyboard[0x3] = 0;
    else if(key == '4') Keyboard[0xC] = 0;

    else if(key == 'q') Keyboard[0x4] = 0;
    else if(key == 'w') Keyboard[0x5] = 0;
    else if(key == 'e') Keyboard[0x6] = 0;
    else if(key == 'r') Keyboard[0xD] = 0;

    else if(key == 'a') Keyboard[0x7] = 0;
    else if(key == 's') Keyboard[0x8] = 0;
    else if(key == 'd') Keyboard[0x9] = 0;
    else if(key == 'f') Keyboard[0xE] = 0;

    else if(key == 'z') Keyboard[0xA] = 0;
    else if(key == 'x') Keyboard[0x0] = 0;
    else if(key == 'c') Keyboard[0xB] = 0;
    else if(key == 'v') Keyboard[0xF] = 0;
}

上述代碼需要注意的是原作者給出了兩種繪圖方式。還有關於CHIP8的鍵盤,映射方式如下:

Keypad                   Keyboard
+-+-+-+-+                +-+-+-+-+
|1|2|3|C|                |1|2|3|4|
+-+-+-+-+                +-+-+-+-+
|4|5|6|D|                |Q|W|E|R|
+-+-+-+-+       =>       +-+-+-+-+
|7|8|9|E|                |A|S|D|F|
+-+-+-+-+                +-+-+-+-+
|A|0|B|F|                |Z|X|C|V|
+-+-+-+-+                +-+-+-+-+

最後編譯生成可執行代碼,然後運行遊戲應用

./mychip8 pong2.c8

這是一個打乒乓的遊戲,運行效果如下,如果沒有接着球的話,命令終端就會打印出BEEP!
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章