※ 주의
소스 그냥 드래그 해서 복사하시면 라이브러와 ddraw.h 파일 다시 지정
해주서야 합니다.
그림 파일은 test.bmp로 변환 해야 합니다. 용량문제로 인하여 jpg를 올립니다.
///////////////////////////////////////////////////
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// 필요한 것만 골라서 include 시켜주는 명령입니다.
// 빌드의 작업시간을 줄여 줍니다.
//////////////////////////// //////////////////////
#include "ddraw.h"
#define DW_WIDTH 1024
#define DW_HEIGHT 768
#define DW_BPP 16
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code)&0x8000)?1:0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code)&0x8000)?0:1)
// 키보드 입력 define입니다.
/*
wParam으로 키를 입력 받을경우 해본 사람은 알겠지만 계속 눌러 보세염
그럼 케릭터의 이동이 한번 끈겼다가 이동하는데 그것도 느리죠.
GetAsyncKeyState()함수는 키보드 입력을 즉시 체크하기 때문에 굉장히 빠릅니다.
이 소스에서는 딜레이를 안줬지만 게임을 만들때에는 키보드로 케릭터를 이동시키게
되면 꼭 딜레이를 줘야 합니다. 아니면 엄청 빠른 케릭터의 이동을 볼수 있죠 ㅡㅡㅋ
*/
#define SafeRelease(x) if (x) { x->Release(); x=NULL; }
// DirectX 객체를 지워줄때 사용하는 define 입니다.
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LPSTR szAppName = "Fist";
LPDIRECTDRAW7 m_pDD = NULL;
LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer = NULL;
LPDIRECTDRAWSURFACE7 m_pddsBackBuffer = NULL;
LPDIRECTDRAWSURFACE7 m_pBmp = NULL; // 그림을 저장할 곳입니다.
RECT m_rwBack;
LPDIRECTDRAWSURFACE7 bitmap_surface(LPCTSTR file_name) // BitMap을 로드 하는 함수.API지식이 필요.
{
// API에서는 그림을 번갈아 출력할때는 메모리 DC에 그림을 그려 넣고 화면 DC에 결과면 복사하여
//출력합니다. 그렇게 해서 화면의 깜빡거림이나 그림을 그리는 과정이 안보이게 하는거죠.
HDC hdc;
HBITMAP bit;
LPDIRECTDRAWSURFACE7 surf;
bit=(HBITMAP) LoadImage(NULL,file_name,IMAGE_BITMAP,0,0, LR_DEFAULTSIZE|LR_LOADFROMFILE);
if (!bit)
return NULL;
BITMAP bitmap;
GetObject( bit, sizeof(BITMAP), &bitmap ); //비트맵의 키기를 알아 오기 위해사용.
int surf_width=bitmap.bmWidth; // 그림의 가로 크기
int surf_height=bitmap.bmHeight; // 그림의 세로 크기
HRESULT ddrval;
DDSURFACEDESC2 ddsd;
ZeroMemory(&ddsd,sizeof(ddsd)); // 메모리 초기화(쓰레기값을 지워야죠)
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
ddsd.dwWidth = surf_width;
ddsd.dwHeight = surf_height;
ddrval=m_pDD->CreateSurface(&ddsd,&surf,NULL);
if (ddrval!=DD_OK) {
DeleteObject(bit);
return NULL;
} else {
surf->GetDC(&hdc);
HDC bit_dc = CreateCompatibleDC(hdc);
/*
HDC CreateCompatibleDC(HDC hdc);
인수로 주어진 hdc와 호환되는 메모리 DC를 생성한다.
여기서 호환된다는 뜻은 색상 포맷이 같다는 뜻이며 색상 포맷이 같은 DC끼리는 비트맵을 전송할 수 있다.
화면 DC는 메모리 상에 존재하는 그리기 표면이다. 실제 화면 DC와 마찬가지로 모든 GDI 출력 함수를
사용할 수 있으므로 프로그램 내부에서 미리 그리기를 할 때 메모리 DC를 사용한다.
*/
SelectObject(bit_dc,bit);
//그리기에 사용할 GDI 오브젝트를 변경하고자 할 때 오브젝트를 만든 후 이 함수로 DC에 선택해 주어야 한다.
BitBlt(hdc,0,0,surf_width,surf_height, bit_dc,0,0,SRCCOPY);
//하나의 DC에 있는 비트맵을 다른 DC로 복사하는 비트맵 전송함수이다, surf에 bit_dc를 복사
surf->ReleaseDC(hdc);
DeleteDC(bit_dc);
}
DeleteObject(bit);
return surf;//LPDIRECTDRAWSURFACE7 이게 포인터형이기 때문에 주소를 리턴하겠죠.
}
int DrawImage()
{
m_rwBack.top = 0;
m_rwBack.bottom = 768;
m_rwBack.left = 0;
m_rwBack.right = 1024;
//m_pddsBackBuffer->Blt(&m_rwBack,m_pBmp,NULL,DDBLT_WAIT,NULL);
m_pddsBackBuffer->BltFast(0, 0, m_pBmp, &m_rwBack, NULL);
/*
그림 Surface를 백버퍼에 복사할 때 사용 하는 두가지 함수 Blt(), BltFast()
Blt() 함수는 반사, 확대 ,클리핑 등의 기능을 지원한다.
반면 BltFast()는 그런 기능들을 제한하고 , 좀더 빠른 속도로 전송한다.
HRESULT Blt ( LPRECT lpDestRect , LPDIRECTDRAWSURFACE lpDDSrcSurface ,
LPRECT lpSrcRect , DWORD dwFlags , LPDDBLTFX lpDDBltFx ) ;
lpDestRect : RECT 포인터 (m_pBmp의 면에서 그림을 잘라 오는 좌표)
lpDDScrSurface : 그림 Surface
lpScrRect : 복사될 면의 사각형에 대한 RECT 포인터
dwFlags : 수행할 비트전송의 형태와 하드웨어가 사용될 때 대기할것인지를 지정
(DDBLT_ASYNC, DDBLT_WAIT, DDBLT_COLORFILL, DDBLT_DDBLT_DDFX, DDBLT_KEYDEST, DDBLT_KEYSRC)
lpDDBltFx : Blt 함수의 가타 효과를 정의하는 DDBLTFX의 포인터
HRESULT BltFast ( DWORD dwX , DWORD dwY , LPDIRECTDRAWSURFACE3 lpDDSrcSurface,
LPRECT lpSrcRect , DWORD dwTrans );
dwX : 시작점 좌표 x
dwY : 시작점 좌표 y
lpDDSrcSurface : 그림 Surface
lpSrcRect : RECT 포인터 (m_pBmp의 면에서 그림을 잘라 오는 좌표)
dwTrans : 비트 전송시 배경색을 염두에 둘건지 직접 복사 할것인지를 지정
*/
return 0;
}
static void UpdateFrame(HWND hWnd) {
////////백버퍼 Clear///////////
DDBLTFX ddbltfx;
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = 0;
m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
//////////////////////////////////////////////////////////////////////
DrawImage();
m_pddsFrontBuffer->Flip( NULL, 0 ); //앞면과 뒷면을 바꿔 버린다.
}
int Free_Direct(void)
{
SafeRelease(m_pddsFrontBuffer);
SafeRelease(m_pDD);
SafeRelease(m_pBmp);
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASSEX WndClass;
WndClass.cbSize = sizeof(WndClass);
WndClass.style
= CS_HREDRAW |
CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
WndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&WndClass);
hWnd=CreateWindowEx(WS_EX_TOPMOST, szAppName, "Draw", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
HRESULT hr;
if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD, IID_IDirectDraw7, NULL ) ) )
return E_FAIL;
hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
if( FAILED(hr) ) return E_FAIL;
if( FAILED( m_pDD->SetDisplayMode( DW_WIDTH, DW_HEIGHT, DW_BPP, 0, 0 ) ) ) return E_FAIL;
////////// 앞면 만들기(Primary Surface라고 하죠.)////////////////////////
DDSURFACEDESC2 ddsd;
ZeroMemory( &ddsd, sizeof( ddsd ) ); //메모리 초기화
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
ddsd.dwBackBufferCount = 1; //백버퍼 1개 만들꺼라는걸 지정.
if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
return E_FAIL;
/////////////////////////////////////////////////////////////////////////////
////////////////////////// 뒷면(Back Surface)만들기 ////////////////////////////////////
DDSCAPS2 ddscaps;
ZeroMemory( &ddscaps, sizeof( ddscaps ) );
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps, &m_pddsBackBuffer ) ) )
return E_FAIL;
//앞면이 뒷면을 첨부 하도록 만든다.(GetAttachedSurface()함수)
/////////////////////////////////////////////////////////////////////////////////////////
m_pBmp=bitmap_surface("test.bmp"); //그림 불러오기
if (!m_pBmp) return FALSE;
while( TRUE )
{
if( PeekMessage( &Message, NULL, 0, 0, PM_NOREMOVE ) )
{
if( 0 == GetMessage(&Message, NULL, 0, 0 ) )
return (int)Message.wParam;
TranslateMessage( &Message );
DispatchMessage( &Message );
}
else
{
if (!KEYUP(VK_ESCAPE)) PostMessage(hWnd, WM_CLOSE, 0, 0);
// ESC 키가 눌리면 프로그램을 종료 한다.
UpdateFrame(hWnd); // 이 함수를 계속 읽습니다.
}
}
return Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
case WM_DESTROY :
Free_Direct();
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam) );
}