블로그 이미지
대갈장군

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2008. 2. 23. 01:18 프로그래밍/DirectX
이제까지는 멈춰있는 스프라이트만 봤지요. 2차원 영상이라면 정지해 있는게 정상 아닌가? 어쨌든 이번 장에서는 움직이게 만든단다. 2차원 영상이 이리저리 움직이는데 어떻게 로딩하고 어떻게 프로그래밍하는지 알아보자.

1. Rectangles
왜 갑자기 사각형 이야기가 나오는 거지? 사각형은 매우 쉽지만 중요한 부분이란다. C++에서는 사각형을 표현할때 RECT 구조체를 이용하는데 이것은 4개의 LONG값을 가진다. top, left, bottom, right 4개의 값을 사용하여 4각형을 표현한다. 각각의 값은 어디서 부터 얼마나 떨어져 있는지를 나타낸다.

Image 1.1 - DirectGrid.png Displayed in DirectX

Image 3.1 - The Four Values of RECT

이 구조체의 정의를 살펴보면,
typedef struct _RECT
{
    LONG left;    // the left value
    LONG top;    // the top value
    LONG right;    // the right value
    LONG bottom;    // the bottom value
} RECT, *PRECT;

이고 이것을 사용하는 예를 보자면,

RECT rectangle = {100, 100, 300, 250};    // create the rectangle in Image 3.1

이 될것이다.

초기값을 설정하거나 중간에 값을 변경하기 위해서는 SetRect 함수를 사용하면 된다는 구나.

RECT rectangle;    // create the rectangle
SetRect(&rectangle, 100, 100, 300, 250);    // initialize the rectangle

2. Animation with Sprites
근데 어떻게 이 rect 구조체가 animation을 만든단 말인가? 일단 Draw 함수를 다시 한번 살펴보자.

HRESULT Draw(LPDIRECT3DTEXTURE9 pTexture,
             CONST RECT* pSrcRect,
             CONST D3DXVECTOR3* pCenter,
             CONST D3DXVECTOR3* pPosition,
             D3DCOLOR Color);

두번째 인자를 보면 CONST RECT* pSrcRect라고 되어 있는데 RECT 구조체에 대한 포인터다.이 RECT 구조체는 그려져야할 스프라이트의 일부를 담고 있다. 예를 들면 다음 그림처럼 앞장에서 그렸던 그리드 중에 일부만 선택적으로 보여 줄 수도 있다는 말. (원래는 NULL이었음)

Image 1.1 - DirectGrid.png Displayed in DirectX

Image 3.2 - Only Some of Panel2.png

물론 이 부분이 들어감으로써 아주 놀라운 변화를 줄수는 있다만 이게 어떻게 애니매이션이 되지? 흠. 그러니까 아주 긴 (위로든 아래로든) 그림이 있는데 그 그림은 사실 연속된 화면의 컷들이다. 각각의 컷은 핫 핑크색을 배경색으로 해서 중간쯤에 움직이는 물체 (우리가 보여주길 원하는 것) 가 존재한다.

내 생각에는 배경색이 핫 핑크이므로 color key를 이용하면 간단히 제거 가능할 테고 중간 주변에 물체를 그려내고 있으므로 한 프래임씩 RECT 구조체의 값을 바꿔가면서 보여주면 애니매이션이 될것이다.

아래가 간단한 연속 컷 화면의 예인데 너무 커서 겨우 3컷 정도만 보인다.

Image 1.1 - DirectGrid.png Displayed in DirectX

Image 3.3 - Part of the Animation Strip

자, 1번 프래임은 다음과 같은 화면일 것이고,

Image 1.1 - DirectGrid.png Displayed in DirectX

Image 3.4 - The First Frame

2번 프래임은 다음과 같을 건데 (좌측으로부터 181 픽셀이 증가한 위치부터 시작)


Image 1.1 - DirectGrid.png Displayed in DirectX

Image 3.5 - The Second Frame

이런식으로 착착 다음 프레임을 보여주게 될것이다.

3. The Finished Program

// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>

// define the screen resolution and keyboard macros
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

// global declarations
LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class
LPD3DXSPRITE d3dspt;    // the pointer to our Direct3D Sprite interface

// sprite declarations
LPDIRECT3DTEXTURE9 sprite;    // the pointer to the sprite

// function prototypes
void initD3D(HWND hWnd);    // sets up and initializes Direct3D
void render_frame(void);    // renders a single frame
void cleanD3D(void);    // closes Direct3D and releases memory

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC)WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = L"WindowClass";

    RegisterClassEx(&wc);

    hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
                          WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                          NULL, NULL, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);

    // set up and initialize Direct3D
    initD3D(hWnd);

    // enter the main loop:

    MSG msg;

    while(TRUE)
    {
        DWORD starting_point = GetTickCount();

        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        render_frame();

        // check the 'escape' key
        if(KEY_DOWN(VK_ESCAPE))
            PostMessage(hWnd, WM_DESTROY, 0, 0);

        while ((GetTickCount() - starting_point) < 25);
    }

    // clean up DirectX and COM
    cleanD3D();

    return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            } break;
    }

    return DefWindowProc (hWnd, message, wParam, lParam);
}


// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = FALSE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = SCREEN_WIDTH;
    d3dpp.BackBufferHeight = SCREEN_HEIGHT;


    // create a device class using this information and the info from the d3dpp stuct
    d3d->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &d3ddev);

    D3DXCreateSprite(d3ddev, &d3dspt);    // create the Direct3D Sprite object

    D3DXCreateTextureFromFileEx(d3ddev,    // the device pointer
                                L"Panel3.png",    // the file name
                                D3DX_DEFAULT,    // default width
                                D3DX_DEFAULT,    // default height
                                D3DX_DEFAULT,    // no mip mapping
                                NULL,    // regular usage
                                D3DFMT_A8R8G8B8,    // 32-bit pixels with alpha
                                D3DPOOL_MANAGED,    // typical memory handling
                                D3DX_DEFAULT,    // no filtering
                                D3DX_DEFAULT,    // no mip filtering
                                D3DCOLOR_XRGB(255, 0, 255),    // the hot-pink color key
                                NULL,    // no image info struct
                                NULL,    // not using 256 colors
                                &sprite);    // load to sprite

    return;
}


// this is the function used to render a single frame
void render_frame(void)
{
    // clear the window to a deep blue
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0);

    d3ddev->BeginScene();    // begins the 3D scene

    d3dspt->Begin(D3DXSPRITE_ALPHABLEND);    // // begin sprite drawing with transparency

    // DRAW THE SPRITE FRAME

    // count from 0 to 22 to determine the current frame
    static int frame = 21;    // start the program on the final frame
    if(KEY_DOWN(VK_SPACE)) frame=0;     // when the space key is pressed, start at frame 0
    if(frame < 21) frame++;     // if we aren't on the last frame, go to the next frame

    // calculate the x-position
    int xpos = frame * 182 + 1;

    // draw the selected frame using the coordinates
    RECT part;
    SetRect(&part, xpos, 0, xpos + 181, 128);

    D3DXVECTOR3 center(0.0f, 0.0f, 0.0f);    // center at the upper-left corner
    D3DXVECTOR3 position(50.0f, 50.0f, 0.0f);    // position at 50, 50 with no depth
    d3dspt->Draw(sprite, &part, &center, &position, D3DCOLOR_ARGB(127, 255, 255, 255));

    d3dspt->End();    // end sprite drawing

    d3ddev->EndScene();    // ends the 3D scene

    d3ddev->Present(NULL, NULL, NULL, NULL);

    return;
}


// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
    sprite->Release();
    d3ddev->Release();
    d3d->Release();

    return;
}





posted by 대갈장군