[WinAPI] 특정 색상 투명하게 처리(LWA_COLORKEY)

오늘은 대화상자의 특정 색을 투명하게 처리하겠습니다.

결론만 말씀 드리면 제일 핵심적인 코드는 아래와 같습니다.

LONG_PTR lExtStyle = ::GetWindowLongPtr( m_hWnd, GWL_EXSTYLE ); // 현재 스타일 얻어오기
::SetWindowLongPtr( m_hWnd, GWL_EXSTYLE, lExtStyle | WS_EX_LAYERED );	// 투명 속성 추가
::SetLayeredWindowAttributes( m_hWnd, RGB(0,255,0), 0, LWA_COLORKEY );	// 특정 색(RGB(0, 255, 0)을 투명 처리

이 속성을 설정 하면 RGB(0, 255, 0)은 표시하지 않고 투명하게 처리 됩니다.
저는 이번 글에서 위 코드를 이용하여 게임 캐릭터가 걸어다니는 모습을 어떻게 표시하는지 알아보고자 합니다.
일반적인 도트 게임에서는 게임 캐릭터의 움직임이 리소스로 모두 그려져 있습니다.
아래와 같이 게임 캐릭터가 있다고 봅시다.

캐릭터가 정지해 있는 모습, 오른발을 내딛는 모습, 왼발을 내딛는 모습이 하나의 BMP 파일에 저장되어 있습니다.

개발자는 이 리소스를 읽어다가, 이동 명령이 없을 땐 맨 왼쪽에 가만히 서있는 모습만 출력 하고, 이동 할 때는 자연스럽게 오른발을 내딛는 그림과, 왼발을 내딛는 그림을 번갈아 표시합니다.
그럼과 동시에 배경으로 있는 초록색 부분을 투명 처리합니다.

프로젝트를 하나 생성 하신 후, 위 리소스 파일을 res 폴더에 넣어서 리소스 뷰에 추가해줍니다.

그런 다음 IDB_BITMAP_TEST로 아이디를 변경해 줍니다.

그리고 헤더 파일에 아래와 같이 변수를 선언합니다.

HDC m_hdc; // 그릴 위치
CImage m_img; // BMP 이미지 로드
int m_iStatus; // 캐릭터의 상태 0 : 멈춤, 1 : 오른발, 2 : 왼발

OnInitDialog에 아래와 같이 코딩합니다.

m_hdc = ::GetDC( m_hWnd );
m_img.LoadFromResource( ::AfxGetInstanceHandle(), IDB_BITMAP_TEST );

LONG_PTR lExtStyle = ::GetWindowLongPtr( m_hWnd, GWL_EXSTYLE ); // 현재 스타일 얻어오기
::SetWindowLongPtr( m_hWnd, GWL_EXSTYLE, lExtStyle | WS_EX_LAYERED );	// 투명 속성 추가
::SetLayeredWindowAttributes( m_hWnd, RGB( 0, 255, 0 ), 0, LWA_COLORKEY );	// 특정 색(RGB(0, 255, 0)을 투명 처리

확인 버튼을 더블클릭하여 이벤트 처리 함수를 만든 뒤 아래와 같이 코딩합니다.

void CMFCApplication1Dlg::OnBnClickedOk()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
    // m_hdc 위치의 (0,0)위치에 (가로 20, 세로 40) 크기로 그림.
	m_img.Draw( m_hdc, 0, 0, 20, 40, m_iStatus * 20, 0, 20, 40 ); 
	if ( 0 == m_iStatus )
	{
		m_iStatus = 1;
	}
	else if ( 1 == m_iStatus )
	{
		m_iStatus = 2;
	}
	else if ( 2 == m_iStatus )
	{
		m_iStatus = 1;
	}
}

이미지 크기가 60×40(가로x세로)인데, 세 모션이 있으므로 한 모션당 가로 20, 세로 40 입니다.
그래서 한 모션만 보여주기 위해, m_iStatus 변수를 사용하여 20, 40 크기만 보여준 겁니다.
취소 버튼을 더블클릭하여 이벤트 처리 함수를 만든 뒤 아래와 같이 코딩합니다.

void CMFCApplication1Dlg::OnBnClickedCancel()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	m_iStatus = 0;
	m_img.Draw( m_hdc, 0, 0, 20, 40, m_iStatus * 20, 0, 20, 40 );
}

취소 버튼은 멈춰 있는 상태를 표시합니다.
이 상태로 실행 시킨 후 확인 버튼과 취소 버튼을 눌러 봅니다.

간단하게 구현만 하기위해서 만들었지만, 개념을 익히셔서 클래스화 시킨 후 방향키 입력을 받아서 만들면 게임 캐릭터가 이동하는 것 처럼 만들 수 있습니다.

대화상자가 투명하게 보이는건 아까 설명 드린 함수로 Bitmap에 있는 RGB(0, 255, 0)값을 투명처리 해서 초록색이 보이지 않게 된 것입니다.

LONG_PTR lExtStyle = ::GetWindowLongPtr( m_hWnd, GWL_EXSTYLE ); // 현재 스타일 얻어오기
::SetWindowLongPtr( m_hWnd, GWL_EXSTYLE, lExtStyle | WS_EX_LAYERED );	// 투명 속성 추가
::SetLayeredWindowAttributes( m_hWnd, RGB(0,255,0), 0, LWA_COLORKEY );	// 특정 색(RGB(0, 255, 0)을 투명 처리