2008. 2. 23. 01:18
프로그래밍/DirectX
이제까지는 멈춰있는 스프라이트만 봤지요. 2차원 영상이라면 정지해 있는게 정상 아닌가? 어쨌든 이번 장에서는 움직이게 만든단다. 2차원 영상이 이리저리 움직이는데 어떻게 로딩하고 어떻게 프로그래밍하는지 알아보자.
1. Rectangles
왜 갑자기 사각형 이야기가 나오는 거지? 사각형은 매우 쉽지만 중요한 부분이란다. C++에서는 사각형을 표현할때 RECT 구조체를 이용하는데 이것은 4개의 LONG값을 가진다. top, left, bottom, right 4개의 값을 사용하여 4각형을 표현한다. 각각의 값은 어디서 부터 얼마나 떨어져 있는지를 나타낸다.
Image 3.1 - The Four Values of RECT
이 구조체의 정의를 살펴보면,
이고 이것을 사용하는 예를 보자면,
이 될것이다.
초기값을 설정하거나 중간에 값을 변경하기 위해서는 SetRect 함수를 사용하면 된다는 구나.
2. Animation with Sprites
근데 어떻게 이 rect 구조체가 animation을 만든단 말인가? 일단 Draw 함수를 다시 한번 살펴보자.
두번째 인자를 보면 CONST RECT* pSrcRect라고 되어 있는데 RECT 구조체에 대한 포인터다.이 RECT 구조체는 그려져야할 스프라이트의 일부를 담고 있다. 예를 들면 다음 그림처럼 앞장에서 그렸던 그리드 중에 일부만 선택적으로 보여 줄 수도 있다는 말. (원래는 NULL이었음)
Image 3.2 - Only Some of Panel2.png
물론 이 부분이 들어감으로써 아주 놀라운 변화를 줄수는 있다만 이게 어떻게 애니매이션이 되지? 흠. 그러니까 아주 긴 (위로든 아래로든) 그림이 있는데 그 그림은 사실 연속된 화면의 컷들이다. 각각의 컷은 핫 핑크색을 배경색으로 해서 중간쯤에 움직이는 물체 (우리가 보여주길 원하는 것) 가 존재한다.
내 생각에는 배경색이 핫 핑크이므로 color key를 이용하면 간단히 제거 가능할 테고 중간 주변에 물체를 그려내고 있으므로 한 프래임씩 RECT 구조체의 값을 바꿔가면서 보여주면 애니매이션이 될것이다.
아래가 간단한 연속 컷 화면의 예인데 너무 커서 겨우 3컷 정도만 보인다.
Image 3.3 - Part of the Animation Strip
자, 1번 프래임은 다음과 같은 화면일 것이고,
Image 3.4 - The First Frame
2번 프래임은 다음과 같을 건데 (좌측으로부터 181 픽셀이 증가한 위치부터 시작)
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, ¢er, &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;
}
1. Rectangles
왜 갑자기 사각형 이야기가 나오는 거지? 사각형은 매우 쉽지만 중요한 부분이란다. C++에서는 사각형을 표현할때 RECT 구조체를 이용하는데 이것은 4개의 LONG값을 가진다. top, left, bottom, right 4개의 값을 사용하여 4각형을 표현한다. 각각의 값은 어디서 부터 얼마나 떨어져 있는지를 나타낸다.
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;
{
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
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,
CONST D3DXVECTOR3* pCenter,
CONST D3DXVECTOR3* pPosition,
D3DCOLOR Color);
두번째 인자를 보면 CONST RECT* pSrcRect라고 되어 있는데 RECT 구조체에 대한 포인터다.이 RECT 구조체는 그려져야할 스프라이트의 일부를 담고 있다. 예를 들면 다음 그림처럼 앞장에서 그렸던 그리드 중에 일부만 선택적으로 보여 줄 수도 있다는 말. (원래는 NULL이었음)
Image 3.2 - Only Some of Panel2.png
물론 이 부분이 들어감으로써 아주 놀라운 변화를 줄수는 있다만 이게 어떻게 애니매이션이 되지? 흠. 그러니까 아주 긴 (위로든 아래로든) 그림이 있는데 그 그림은 사실 연속된 화면의 컷들이다. 각각의 컷은 핫 핑크색을 배경색으로 해서 중간쯤에 움직이는 물체 (우리가 보여주길 원하는 것) 가 존재한다.
내 생각에는 배경색이 핫 핑크이므로 color key를 이용하면 간단히 제거 가능할 테고 중간 주변에 물체를 그려내고 있으므로 한 프래임씩 RECT 구조체의 값을 바꿔가면서 보여주면 애니매이션이 될것이다.
아래가 간단한 연속 컷 화면의 예인데 너무 커서 겨우 3컷 정도만 보인다.
Image 3.3 - Part of the Animation Strip
자, 1번 프래임은 다음과 같은 화면일 것이고,
Image 3.4 - The First Frame
2번 프래임은 다음과 같을 건데 (좌측으로부터 181 픽셀이 증가한 위치부터 시작)
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, ¢er, &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;
}
'프로그래밍 > DirectX' 카테고리의 다른 글
[DX Tutorial - Game Display ] Lessong 5: Buildig a Game Display (2) | 2008.02.23 |
---|---|
[DX Tutorial - Game Display] Lesson 4: Adding Text to the Display (0) | 2008.02.23 |
[DX Tutorial - Game Display] Lesson 2: More about Sprites (0) | 2008.02.20 |
[DX Tutorial - Game Display] Lession 1: Using Sprites (0) | 2008.02.20 |
[DX Tutorial - Mesh] Lesson 3: Loading Textured Meshes (0) | 2008.02.20 |