ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DirectX7 - Surface 생성
    프로그래밍/DirectDraw 2005. 6. 24. 05:37

    DirectX7 - Surface 생성

     

    DirectDraw의 핵심기능 하면 바로 비디오 모드 세팅과 바로 오늘 배울 서페이스 개념입니다.

    비디오 모드 세팅과 서페이스만 배우면 일단은... DirectDraw를 99% 이상은 끝냈다고 봐도 될겁니다.

    더군다나 DirectDraw는 DirectX 8.0부터는 2D 부분과 3D 부분이 DirectGraphics으로 합쳐져서 초반에 개념 잡기가 조금은 힘들지만,

    서페이스 개념은 8.0, 9.0 에서도 마찬가지이므로 이번 시간에 배우는 내용만 잘 숙지하시면 다이렉트의 버전에 상관 없이 같은 방식으로 프로그래밍을 하실 수가 있습니다.


    DirectDraw에 존재하는 Surface의 종류에는 기본적으로 기본 표면과 보조 표면 두가지가 있습니다.

    기본 표면은 반드시 만들어져야 하며, (물론 없어도 되긴 하지만... 제대로 된 프로그램이라면...)

    기본 표면이 있어야 보조 표면을 만들 수가 있습니다.

    또한 기본 표면은 비디오 카드에서 레스터화하는 실제 비디오 메모리와 일치해야 합니다.

    즉, 800*600으로 해상도를 변경했다면 기본 표면의 사이즈 역시 800*600이어야 한다는 뜻입니다.

    모든 기본 표면은 단 하나만 존재 할 수 있으며, 보통은 VRAM 상에 상주합니다.


    그러나 보조 표면의 경우, 일단 표면의 크기에 제한이 없고 VRAM에도 존재 할수 있고 시스템 메모리 상에서도 존재할 수 있으며, 사용자의 메모리가 허용한다면 얼마든지 만들어 낼 수가 있습니다.

    대부분의 경우, 하나나 두개의 보조 표면을 만들어서 기본 표면과 플리핑(Flipping) 하는 더블 버퍼링/트리플 버퍼링이라는 기법을 주로 사용합니다.


    보조 표면을 사용하는 이유는 위에서 말한 더블 버퍼링이나 트리플 버퍼링과 같이 부드러운 애니메이션을 위해 사용하기도 하지만, 때로는 그냥 단지 비트맵들을 미리 로딩해 놓는 창고 역할도 합니다.

    위와 같은 작업을 우리는 보통 로딩이라고 하죠. 그러나 이러한 내용은 나중에 조금더 그럴듯한 게임을 만드는 과정에서 좀더 자세히 살펴보도록 하겠습니다.

     

    표면을 만드는 것은 다음과 같은 과정을 거칩니다.

        1.DDSURFACEDESC2 구조체를 만들고 만들고자 하는 표면의 정보를기술(DESCription)합니다.

        2. IDirectDraw7::CreateSurface()함수를 호출해서 표면을 생성합니다.

    순서는 간단해 보이지만 의외로 이해하기 힘든 개념일 수도 있습니다.

    DDSURFACEDESC2를 MSDN에서 찾아보면 멤버가 엄청나게 많은 것을 확인 할 수 있습니다.

     

    * 조금은 복잡해 보이는 DDSURFACEDESC2 구조체.

    typedefstruct_DDSURFACEDESC2{
        DWORD          dwSize;
        DWORD          dwFlags;
        DWORD          dwHeight;
        DWORD          dwWidth;

       union
        {
           LONG       lPitch;
            DWORD      dwLinearSize;
        };
        DWORD          dwBackBufferCount;
       union
        {
            DWORD      dwMipMapCount;
            DWORD      dwZBufferBitDepth;
            DWORD      dwRefreshRate;
        };
       DWORD          dwAlphaBitDepth;
        DWORD          dwReserved;
       LPVOID         lpSurface;
        DDCOLORKEY     ddckCKDestOverlay;
        DDCOLORKEY     ddckCKDestBlt;
        DDCOLORKEY     ddckCKSrcOverlay;
       DDCOLORKEY     ddckCKSrcBlt;
        DDPIXELFORMAT  ddpfPixelFormat;
       DDSCAPS        ddsCaps;
    }DDSURFACEDESC2,FAR*LPDDSURFACEDESC2
     

    어때요. 상당히 복잡하죠?

     

    그러나 여러분께는 제가 있으니 걱정하지 않으셔도 됩니다^^;


    제가 위 구조체에서 빨간색 볼드체로 지정해 놓은 부분만 유심히 보시면 됩니다.

    가장 윗줄에 있는dwSize의 경우는 다들 아시다 시피 구조체의 사이즈를 기록해 주시면 됩니다.

    DirectX의 모든 구조체에서 한번도 빠짐 없이 나오는 멤버입니다.(정말 입니다. 확인해보시길^^)

    나중에 함수 호출시에 구조체를 역참조(dereferencing)하여 데이터의 양을 정확히 알아내기 위해 사용됩니다.

    우리는 그냥 단순히sizeof()함수를 이용해서 사이즈만 넘겨주면 됩니다.


    두번째로 나오는dwFlags의 경우, DirectDraw에게 우리가 데이터를 기록해 넣을 필드를 알려줄때 사용합니다.

    dwFlags에 대입할수 있는 플래그의 종류는 아래와 같습니다

     

    * dwFlags에 대입될수 있는 Flag 값들.

    DDSD_ALPHABITDEPS dwAlphaBitDepth 멤버가 유효함을 나타낸다. 
    DDSD_BACKBUFFERCOUNT dwBackBufferCount 멤버가 유효함을 나타낸다. 
    DDSD_CAPS ddsCaps 멤버가 유효함을 나타낸다. 
    DDSD_CKDESTBLT ddckCKDestBlt 멤버가 유효함을 나타낸다. 
    DDSD_CKDESTOVERLAY ddckCKDestOverlay 멤버가 유효함을 나타낸다. 
    DDSD_CKSRCBLT ddckCKDestSrcBlt 멤버가 유효함을 나타낸다. 
    DDSD_CKSRCOVERLAY ddckCKSrcOverlay 멤버가 유효함을 나타낸다. 
    DDSD_HEIGHT dwHeight 멤버가 유효함을 나타낸다. 
    DDSD_LINEARSIZE dwLinearSize 멤버가 유효함을 나타낸다. 
    DDSD_LPSURFACE IpSurface 멤버가 유효함을 나타낸다. 
    DDSD_MIPMAPCOUNT dwMipMapCount 멤버가 유효함을 나타낸다. 
    DDSD_PITCH IPitch 멤버가 유효함을 나타낸다. 
    DDSD_PIXELFORMAT ddpfPixelFormat 멤버가 유효함을 나타낸다. 
    DDSD_REFRESHRATE dwRefreshRate 멤버가 유효함을 나타낸다. 
    DDSD_TEXTURESTAGE dwTextureStage 멤버가 유효함을 나타낸다. 
    DDSD_WIDTH dwWidth 멤버가 유효함을 나타낸다. 

    플래그가 많다고 당황해 할 필요는 절대 없습니다.

     

    만약 dwWidth와 dwHeight 필드에 값을 대입 하고 싶다면,

    ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT 과 같이 선언해 주시면 됩니다.

    즉, 우리가 필요로 하는 멤버의 종류를 기록해 주면 된다는 것이지요.

    위 플래그들은 강좌를 진행해 나가면서 차차 하나하나 설명해 드리도록 할 테니 절대로 이 플래그에 대해서 걱정하시거나 고민하시지 마시길 바랍니다.


    다시 DDSURFACEDESC2 구조체의 멤버로 눈길을 돌려서,

    dwWidth/dwHeight멤버는 생성할 표면의 너비와 폭을 픽셀 단위로 지정해 주는 것인데요.

    사이즈를 지정하지 않는다면, 현재 화면의 해상도와 동일한 크기로 생성 됩니다.


    dwBackBufferCount는 기본 표면에 연결되는 보조 표면의 갯수를 기록해주는 필드인데요. 보통 BackBuffer는 1개나 2개 정도를 생성하게 됩니다.

    더블 버퍼링에 대해서는 다음시간에 자세하게 알아볼 것입니다.


    ddckCKDestBlt/ddckCKSrcBlt는 대상 표면의 컬러키를 지정하는 부분인데, 나중에 블리팅 연산에서 사용됩니다. 이건 조금 더 후에 자세히 알아보도록 할 것입니다.


    그리고 마지막으로ddsCaps필드가 있는데, 이 필드는 현재 생성하고자 하는 표면의 속성을 나타내는데 사용됩니다.

    이 ddsCaps 필드는 구조체 안에 중첩된 또 하나의 구조체인데, 구조체 원형은 아래와 같습니다.

     

    typedefstruct_DDSCAPS2
        {
            DWORD dwCaps;
            DWORD dwCaps2;
            DWORD dwCaps3;
            DWORD dwCaps4;
        }DDSCAPS2,FAR*LPDDSCAPS2;

    대부분은 첫번째인 dwCaps만 선택하게 될 것입니다.

    dwCaps2는 3D 프로그래밍시 쓰이며, 나머지 3번과 4번은 차후 확장용(future expansion) 변수이며, 지금은 쓰이지 않는다네요.

    ddsCaps 구조체의 멤버인 dwCaps 안에 들어갈수 있는 플래그는 아래와 같습니다.

     

    * DirectDraw 표면의 속성 설정 플래그.

    DDSCAPS_BACKBUFFER 이 표면이 표면 플리핑 구조체의 백 버퍼임을 나타냅니다.
    DDSCAPS_COMPLEX 이 표면이 플리핑 체인을 만들기 위해 기본 표면과 하나 이상의 백버퍼를 가지고 있음을 나타냅니다.
    DDSCAPS_FLIP 이 표면이 표면 플리핑 구조체의 일부임을 나타냅니다.
    DDSCAPS_OFFSCREENPLAIN 이 표면이 그리기 위한 화면 표면이 아님을 나타냅니다. 
    주로 스프라이트 이미지를 미리 불러와 저장해두는 창고의 의미가 강한 표면 속성입니다.
    DDSCAPS_PRIMARYSURFACE 이 표면이 기본 표면임을 나타냅니다.
    이 표면은 실제 사용자에게 보여지는 표면입니다.
    DDSCAPS_SYSTEMMEMORY 이 표면의 메모리가 시스템 메모리 상에 할당 되어 있음을 나타냅니다. 
    DDSCAPS_VIDEOMEMORY 이 표면이 그래픽카드의 VRAM 상에 존재함을 나타냅니다.

    위 플래그에 대한 설명은 따로 하지 않겠습니다.

    앞으로 차차 예제 소스를 통해 하나 하나 설명을 하는 것이 이해도 훨씬 쉬울테니까요.


    어쨋든 위에서 배운 내용을 토대로, DDSURFACEDESC2 구조체의 멤버들을 채워주신 후에는,

    HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfaceDesc2,
                                        LPDIRECTDRAWSURFACE7 FAR* lplpDDSurface,
                                        IUnknown FAR* pUnkOuter);


    위의 CreateSurface() 함수를 호출해 주시면 됩니다.

     

    즉... 우리가 하나의 기본 표면을 생성해 주고 싶다면,

    * 기본 표면 생성.

    DDSURFACEDESC2 ddsd;
    LPDIRECTDRAWSURFACE7 lpddSPrimary;

    ddsd.dwSize =sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;// ddsCaps 멤버를 사용 할 것임을 DirectDraw에게 알립니다.
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;// 이 표면이 기본 표면임을 알립니다.

    lpdd->CreateSurface(&ddsd, &lpddSPrimary, NULL);// 표면 생성. 

    어때요? 우리가 배운 내용은 되게 어려운 내용인 것 같지만, 막상 구현을 해보니 엄청나게 간단하지요?

    오늘 배운 내용을 확실히 이해를 못하셨어도 계속해서 여러 프로그램을 만들어 나가는 과정에서 서페이스를 만들어가는 과정이 아주 당연하게 느껴지실 날이 올겁니다^^


    다음 시간에는 Primary Surface와 Back Buffer를 직접 만들어보고 그걸 Flip시켜 보는 소스를 한번 보며 공부를 해보도록 하겠습니다.

    오늘 배운 내용이 이해가 완전히 가지 않으셨다고 다음 강좌를 보지 않고 포기하시는 그런 행동은 제발 하지 말아주시길 바랍니다.

    뭐든지 한번에 이해할수는 없으니까요.

    계속해서 구현을 하면서 몸으로 느끼는 수 밖에 없습니다.^^


    그럼 여러분 감사하구요. 다음 시간에 뵈요^^

     

     

    자료출처: 공병철님의 DirectX를 이용한 Windows Game Programming 강좌

    댓글