게임모드에 대해서

GLUT 에 대해서 설명한 맨페이지(Linux 에 있는 도움말)에 따르면 GLUT 의 게임모드는 고성능의 풀스크린 렌더링이 가능하도록 설계되었다고 적혀있습니다. 하지만 어디에나 함정이 있기 마련이죠. GLUT 의 기능 중에서 팝업메뉴와 서브윈도우 기능은 좋은 성능을 내는데 걸림돌이 됩니다. 이번 장에서는 GLUT 가 제공하는 게임모드에 대해서 알아보겠습니다. 참고로 이 장의 설명들은 맨페이지나 GLUT 의 소스코드에서 거의 대부분 참고한 것입니다. 제가 이 글을 쓸 때만해도 GLUT 의 게임모드에 대해서 공식적인 문서가 없었고 다른 싸이트에서도 이 주제에 대한 튜토리얼이 없었습니다. 그래서 게임모드 주제에 대해서 쓴 이 글의 정확성을 100% 보장할 수는 없습니다. 저는 게임모드에 대해서 얼마의 식견을 가지고서 실행할 수 있는 데모를 만들었습니다. 하지만 여러 다른 하드웨어를 갖춘 시스템에서 충분히 테스트하지 못했기 때문에 예제에 애매한 점이나 잘못된 버그가 있을지도 모릅니다. 이 튜토리얼의 내용을 바탕으로 어플리케이션을 만들었을 때 이런 문제로 고생하고 있다면 문제에 대한 자세한 정보를 저에게 보내주세요. 그럼 제가 최선을 다해서 살펴보겠습니다. 이미 여러분들 중에 GLUT 의 게임모드에 대해서 잘 아시는 분이 있다면 잘 못된 부분을 수정할 수 있도록 이 글에서 틀린점을 지적해서 제 e-mail(antonio.ramires@lighthouse3d.com)로 보내주셨으면 좋겠습니다.

자~ 이제 약간의 참회도 했으니 이번 장을 시작해보겠습니다. 우선 제일 처음에 해야할 것은 게임모드를 위한 설정을 정의하는 것입니다. 즉 풀스크린으로 할 것인지 아닌지. 이런 설정의 정의는 스크린의 해상도, 픽셀 깊이, 리프레쉬율 등을 포함합니다. 이 말을 다르게 풀어보면, 우리가 원하는 해상도가 뭐든지간에 다 만들 수 있다는 얘기입니다.(물론 하드웨어의 지원 범위 내에서만 가능합니다.) 즉, 현재 해상도로만 풀스크린을 설정하지 않아도 되는 것입니다.

풀스크린을 설정하는 정의는 문자열로 만들어집니다. 다음은 이 문자열의 형식입니다.

"WxH:Bpp@Rr" 

형식 설명:
W - 픽셀 단위의 스크린의 너비입니다.
H - 픽셀 단위의 스크린의 높이입니다.
Bpp - 픽셀당 비트의 수입니다.
Rr - Hz 단위의 화면 리프레쉬율입니다.

다른 것을 알아보기 전에, 이 설정들은 단지 하드웨어에 요청하는 것일 뿐입니다. 만약에 특정 모드가 불가능하다면 그 설정은 무시됩니다.

다음은 특정 해상도를 설정하는 문자열의 예제입니다.

"800x600:32@100" - 800x600 해상도; 32bit 트루컬러; 100Hz; 의 스크린 설정문입니다.
"640x480:16@75" - 640x480 해상도; 16bit 하이컬러; 75Hz; 의 스크린 설정문입니다.

모든 조건(요소)들을 일일이 설정하는 것은 쪼금 괴로운 일입니다. 비록 우리가 스크린 해상도에 대해서 분명하게 알고 있더라도, 특별한 픽셀 깊이나 리프레쉬율을 일일이 설정하기에는 무리가 있을 때가 있습니다. 하지만 다행스러운 것은 우리가 일일이 모든 것을 설정해줄 필요가 없다는 것입니다. 우리는 특정 조건을 빼 놓고 설정할 수 있습니다. 빠진 조건은 GLUT 가 알아서 설정합니다. 다음에 나오는 예제들은 모두 풀스크린을 설정하는 문자열입니다.

"WxH" 
"WxH:Bpp" 
"WxH@Rr" 
"WxH:Bpp@Rr" 
"@Rr" 
":Bpp" 
"Bpp:@Rr"

GLUT 는 순서가 지켜진다면 어떤 조합이든지 다룰 수가 있습니다. 그래서 픽셀당 비트의 수 앞에 리프레쉬율을 설정하는 것은 허용되지 않습니다.

그럼 픽셀깊이와 리프레쉬율등은 고려하지 않고 화면 해상도만 설정하고 싶다면 다음과 같이 쓸 수 있을 것입니다.

"800x600"

아니면 현재 해상도에 픽셀깊이만 32비트로 설정하고 싶다면 다음과 같이 쓸 수 있을 것입니다.

":32"

때로는 리프레쉬율만 바꾸고 싶을 때가 있겠죠.

"@100"

위에서 든 몇가지 예제들이 풀스크린의 설정에 관해서 모든 것을 보여주진 않지만 모두 사용할 수 있는 설정문들입니다.

자~ 이제 게임모드로 들어갈 준비가 되었습니까? 그럼 우선 GLUT 로 풀스크린 설정을 요구해야합니다. 게임모드를 설정하는 GLUT 의 함수는 glutGameModeString 함수입니다. 다음은 이 함수의 설명입니다.

void glutGameModeString(const char *string); 

인자 설명:
string - 위에서 본 설정문처럼 알맞은 조건을 포함한 문자열입니다.

GLUT 는 glutGameModeString 함수에 전달된 인자의 유효성을 검사합니다. 비록 함수가 에러코드를 반환하지 않더라도, 설정모드가 유효한지 검사할 수 있습니다. GLUT 는 게임모드 설정문의 유효성을 검사할 수 있는 함수를 제공합니다. 다음은 이 함수의 설명입니다.

int glutGameModeGet(GLenum info); 

인자 설명:
info - 원하는 정보입니다.

요청한 게임모드가 유효한지 검사하려면 GLUT 에 미리 정의되어 있는 상수 GLUT_GAME_MODE_POSSIBLE 을 info 인자에 전해줘야합니다. 이 경우, 반환값이 게임모드의 유효성을 뜻하는데 0 이 아니면 유효(가능)한 게임모드라는 뜻입니다. 하지만 맨페이지에 있는 GLUT 설명서를 보면 비록 게임모드가 유효하더라도 스크린 설정이 보증되지 않을 경우가 있다고합니다.

위 함수의 반환값이 0 이 아니라고 가정하면 glutEnterGameMode 함수로 게임모드에 진입할 수 있고 또는 적어도 진입을 시도할 수 있습니다. 이 함수가 실제로 스크린을 요구한 설정대로 게임모드를 만듭니다. 다음은 이 함수의 설명입니다.

void glutEnterGameMode(void);

800x600 해상도의 게임모드를 설정하는 GLUT 어플리케이션의 main 함수는 아래처럼 만들 수 있습니다.

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

    /* 
    glutInitWindowPosition(100,100);
    glutInitWindowSize(640,360);
    glutCreateWindow("SnowMen from 3D-Tech");
    */

    // 창의 크기와 위치를 설정하는 위의 함수호출 대신에
    // 게임모드를 설정합니다 
    glutGameModeString("800x600:32");

    // 풀스크린으로 진입합니다.
    if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) 
        glutEnterGameMode();
    else
     {
        printf("The select mode is not available\n");
        exit(1); 
    }

    // 모든 콜백함수들을 등록하고
    // 디스플레이리스트를 만듭니다.
    init();

    glutMainLoop();

    return(0);
}

init 함수는 openGL 을 초기화를 수행하는데 필요한 모든 콜백함수들을 등록합니다. 예를 들어 아래와 같이 만들 수 있습니다.

void init()
{
    glutIgnoreKeyRepeat(1);
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(pressKey);
    glutSpecialUpFunc(releaseKey);
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);
    initScene();
}

어플리케이션을 실행하는 도중에 게임모드와 창모드를 왔다갔다 변환하고 싶을 경우가 있습니다. 다음에 나오는 코드를 사용하면 게임모드에서 창모드로 변환할 수 있습니다. 사용자가 F1 키를 누르면 게임모드로 변환되고 F6 키를 누르면 다시 창모드로 변환됩니다. 이 때 반드시 창의 속성을 다시 정의하고 콜백함수를 등록한 다음, 메인루프로 진입해야합니다.

예제 코드를 보기전에 게임모드를 창모드로 변환시켜주는 함수를 살펴봅시다.

void glutLeaveGameMode(void);

이 함수는 모드를 변환시키는 특수키가 눌렸을 때 작동할 것입니다. 다음은 앞에서 말했던 동작들을 그대로 코드로 옮겨놓은 함수입니다.

void pressKey(int key, int x, int y)
{
    switch (key)
    {
        ...
    case GLUT_KEY_F1: 
        // 해상도와, 색상깊이를 저으이합니다.
        glutGameModeString("640x480:32");
        // 풀스크린으로 진입합니다. 
        if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE))
        {
             glutEnterGameMode();

            // 콜백함수들을 다시 등록합니다.
            init();
        } 
        break; 
    case GLUT_KEY_F6: 
        // 기본창모드로 돌아갑니다.
        glutLeaveGameMode();
        break;
    }
}

위의 함수에는 중요한 내용들이 많이 있습니다. glutEnterGameMode 함수로 게임모드에 진입했을 때 반드시 콜백함수들을 다시 등록해줘야합니다. 그리고 OpneGL 문맥을 다시 정의해줘야합니다. 게임모드는 새로운 창과 같은 것입니다. 이 말은 창모드의 콜백함수들이 게임모드에는 쓸모 없다는 것입니다. 그래서 콜백함수를 사용하려면 다시 등록해줘야 합니다. 거기에다가 OpenGL 문맥을 다시 정의해야합니다. 그리고 창모드의 디스플레이 리스트를 만들었다면 게임모드를 위한 디스플레이 리스트도 다시 만들어줘야합니다.

GLUT 는 아주 좋은 API 라서, 현재 처리하고 있는 일의 상황을 물어볼 수 있도록 프로그래머에게 방법을 제공합니다. 당연히 게임모드가 돌아가는 상황을 알 수 있도록 특별한 함수를 제공하는데 glutGameModeGet 이란 함수입니다. 이 함수의 원형은 이미 위에서 소개했었습니다. 그 때 이 함수의 인자로 GLUT_GAME_MODE_POSSIBLE 값을 전달했었습니다. 그럼 이제 인자에 전달할 수 있는 다른 값들에 대해서 알아봅시다.

glutGameModeGet 함수에 인자로 전달할 수 있는 값이 여러개가 있습니다. 이 값들은 게임모드 프로그래밍을 안전하게 하기 위해서 모두 필요합니다. 각각의 경우에 따라서 반환값이 어떻게 되는지 아래에 적어보았습니다.

마지막 네 개의 설정값들은 게임모드가 실행되고 있을 때 사용할 수 있는 값입니다. 만약에 게임모드를 설정하는 설정문이 유효하지 않다면 glutGameModeGet 함수는 이 설정값들(마지막 네 개의 값)에 대해서 모두 -1 을 반환합니다. 이미 게임모드가 실행되고 있을 때에도 그렇습니다. 예를 들어서 주어진 어플리케이션이 640x480 의 게임모드에서 실행 중에 1600x1200 게임모드로 변경요청을 했는데 실제 하드웨어 능력과 맞지 않아서 유효하지 않은 요구가 된다면 GLUT 는 게임모드의 해상도를 변경하지 않고 640x480 해상도로 게임모드를 유지합니다. 그러나 이 때 높이값을 알아봤을 때 480 값이 반환되지 않고 -1 이 반환됩니다. 실제 높이가 480 이더라도 말이죠.

다음 코드는 glutGameModeGet 함수를 사용하는 예제입니다.

if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) == 0)
    sprintf(currentMode,"Current Mode: Window");
else
    sprintf( currentMode, "Current Mode: Game Mode %dx%d at %d hertz, %d bpp", 
                glutGameModeGet(GLUT_GAME_MODE_WIDTH),
                glutGameModeGet(GLUT_GAME_MODE_HEIGHT),
                glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE),
                glutGameModeGet(GLUT_GAME_MODE_PIXEL_DEPTH) 
    );
}

여기까지가 게임모드에 관해서 제가 알고있는 것들입니다. 게임모드를 사용하는 예제를 만들어 보았습니다. 자세하게 살펴보세요.

Last updated