이제 불러온 이미지를
플레이어 텍스처로 사용을 해 볼까요?
CPlayer 클래스의 헤더 파일에
4번째 줄에서 CTexture 클래스를 전방 선언하여
CTexture 클래스에 변경 사항이 생겨도
굳이 CPlayer 클래스의 헤더 파일에서
CTexture 클래스를 검사하지 않도록 합니다.
어차피 CPlayer 클래스의 소스 파일에서
CTexture 헤더 파일을 참조하고 있기 때문에
CPlayer 클래스의 소스 파일에서
검사를 진행하게 되기 때문이죠.
10번째 줄에는 CTexture형 포인터인,
멤버 m_pTexture가 추가되었습니다.
특정 텍스처를 가리키는 포인터이죠.
이 포인터가 가리킬 텍스처가
바로 플레이어의 텍스처입니다.
멤버 m_pTexture는
플레이어 오브젝트가 생성될 때는
nullptr로 초기화되었다가
바로 동적 할당된 공간을 가리킵니다.
19 ~ 20번째 줄에 의해
지정된 경로에 접근합니다.
그리고 부모 클래스인 CTexture의 멤버 함수인,
Lord 함수를 통해 지정된 경로에
존재하는 이미지를 불러오죠.
CreateCompatibleDC 함수는 인자로 받은
DC와 호환되는 DC를 만들어 반환합니다.
메인 DC를 인자로 넣었으니
메인 DC와 호환되는 DC가
CTexture 클래스의 멤버 m_hdc에
대입되었을 겁니다.
이후 SelectObject 함수를 통해
불러온 텍스처가 저장된 비트맵을
가리키는 m_hBit를 m_hdc가 선택하도록 합니다.
SelectObject 함수가 반환한 것을
HBITMAP으로 형변환하여
HBITMAP형 hPrevBitmap에 대입합니다.
그리고 DeleteObject 함수를 통해
hPrevBitmap를 제거합니다.
이렇게 하는 이유는
DC가 만들어질 때,
기본적으로 1 픽셀의 비트맵을 가리키고 있는데
이는 필요 없으므로 제거해 주기 위해서입니다.
m_hdc에 저장된 DC가 가리키고 있던
비트맵을 제거해 주는 것이죠.
GetObject 함수를 통해
비트맵의 정보를 얻어낼 것입니다.
불러온 텍스처의 크기를 알기 위해서죠.
정보를 알고자 하는 비트맵을 첫 번째 인자로 넣습니다.
세 번째 인자는 첫 번째 인자가 갖고 있는 정보들을
저장하는 버퍼를, 가리키는 포인터입니다.
( 그래서 주솟값을 넘겨주는 겁니다. )
CTexture의 멤버인 m_bitInfo가 바로
불러온 텍스처의 정보들을 저장하는 버퍼이죠.
BITMAP이라는 자료형
위 사진처럼 다양한 정보들을 저장할 수 있습니다.
저장된 정보를 각 멤버에 접근함으로써 얻어낼 수 있는 거죠.
두 번째 인자는 버퍼에 저장할
정보의 크기( 바이트 )를 나타냅니다.
이후 플레이어 오브젝트가 소멸하여
소멸자를 호출하게 되면
플레이어 오브젝트가 갖고 있던
텍스처를 메모리상에서 제거합니다.
이때 가리키는 텍스처가 존재할 때
delete해 주어야 문제가 생기지 않겠죠.
CPlayer 클래스의 헤더 파일을 다시 보시면
14번째 줄에 render 함수가 있습니다.
부모 클래스인 CObject의
render 함수가 가상 함수이기 때문에
플레이어 객체가 render 함수를 호출하면
자신의 render 함수, 즉 14번째 줄에 있는
render 함수가 실행되겠죠.
render 함수의 정의를 살펴보면
먼저 61번째 줄에서 GetPos 함수를 통해
지역 변수 vPlayerPos에 플레이어 오브젝트의
위칫값을 저장합니다.
이후 지역 변수 iWidth와 iHeight에 각각
Width 함수와 Height 함수를 통해서
값을 넣어주고 있습니다.
두 함수는
CTexture가 갖고 있는 멤버 함수로
텍스처의 정보들을 저장하고 있는
멤버 m_bitInfo의 width와 height값을
반환하는 함수이죠.
이때 텍스처의 가로와 세로의 길이가
음수일 수는 없기 때문에 UINT( unsigned int )로
반환하는 모습입니다.
이렇게 해서 지역 변수 iWidth와 iHeight에는 각각
텍스처의 가로, 세로의 길이 저장되겠죠.
67번째 줄에 있는 TransparentBlt 함수를 통해
본격적으로 플레이어 오브젝트에 텍스처를
덮어씌웁니다.
( TransparentBlt 함수는 Windows 헤더 파일에 선언만
되어 있습니다. 선언이 있기 때문에 컴파일 과정에서
오류가 발생하지는 않지만, 실행해 보면 정의가 없기 때문에
링크 과정에서 오류가 발생하게 되죠. 그래서
#pragma comment(lib, "Msimg32.lib") 구문을 추가하여
Windows 헤더 파일 안에 Msimg32.lib 라이브러리까지
참조해야 사용할 수 있습니다. )
첫 번째 인자로 CPlayer의 render 함수가 호출될 때
받은 DC를 넘깁니다. 이 DC는 씬이 초기화될 때부터
계속 넘어왔던 비트맵을 가리키는 DC겠죠?
인자로 넘긴 이 DC가 가리키는 비트맵에
불러온 텍스처를 그리겠다는 의미입니다.
2 ~ 3번째 인자는 텍스처를
붙일 곳의 좌상단 좌푯값입니다.
메인 윈도우와 같은 크기를 하고 있는
비트맵의 어디부터, 우리가 불러온 텍스처를
그려 넣을 것인지 나타내기 위한 것이죠.
플레이어 오브젝트의 x 좌푯값에서
텍스처 가로 길이를 반으로 나눈 값을
뺍니다. 그리고 이 값을 x 좌푯값으로 합니다.
플레이어 오브젝트의 y 좌푯값에서
텍스처 세로 길이를 반으로 나눈 값을
뺍니다. 그리고 이 값을 y 좌푯값으로 하죠.
이때 플레이어의 좌푯값은 float으로
구성되었기 때문에 텍스처의 길이를
반으로 나눈 값을 float으로 형변환한 후에
뺄셈을 진행하고 결과로 나온 값을 다시
int로 형변환하여 인자로 넘깁니다.
TransparentBlt 함수가 int형을
인자로 요구해서 그런 것도 있지만,
아래 그림처럼
좌상단 좌푯값은 음수가
나올 수 있기도 하죠.
물론 메인 윈도우에 크기를
벗어나면 벗어나지 않은 부분만
윈도우상에 출력되겠죠.
4 ~ 5번째 인자는
텍스처가 얼마만큼의 길이를 가진
공간에 붙여 넣을 것인가를 나타냅니다.
텍스처의 전체 가로 길이인 iWidth와
전체 세로 길이인 iHeight의 값을 인자로 넘기면 되겠죠.
첫 번째 인자로 받은 기존 DC는
메인 윈도우에 그릴 비트맵을 가리키고 있었습니다.
6번째 인자는 이 비트맵에
그리고자 하는 텍스처가 저장된
비트맵을 가리키고 있는 DC를 넣으면 됩니다.
7 ~ 8번째 인자는 텍스처가 저장된
비트맵의 좌상단 좌푯값인데
어차피 ( 0, 0 ) 좌푯값에 있는 픽셀부터
전체 픽셀을 기존 DC가 가리키는
비트맵에 그릴 것이므로 0, 0을 넣습니다.
마찬가지로 9번째 인자는 붙여 넣을
텍스처의 길이로, 텍스처 전체를
붙여 넣을 것이므로 전체 가로 길이를 의미하는
iWidth와 전체 세로 길이를 의미하는 iHeight의 값을
인자로 넘기면 되겠죠.
마지막 인자로 RGB를 받습니다.
이것이 BitBlt 함수 대신
TransparentBlt 함수를 사용하는 이유죠.
만약 사용하려는 텍스처가
위 사진과 같다고 합시다.
위 텍스처에서 분홍 배경을 없애고
오직 캐릭터만 윈도우상에 출력하고 싶습니다.
이때 분홍 배경의 정확한 RGB값을
파악한 후 RGB 매크로를 사용하여
마지막 인자로 넘기면 분홍 배경이 제거된
상태로 윈도우에는 캐릭터만 출력될 겁니다.
이제 프로그램을 실행해 보면
불러온 텍스처가 플레이어 오브젝트 위에
덮어씌워진 것을 확인할 수 있으며
플레이어를 움직여도 텍스처가 잘 따라오는 것을
확인할 수 있습니다.
강의 출처 : https://www.youtube.com/watch?v=UdE72OPx3jI&list=PL4SIC1d_ab-ZLg4TvAO5R4nqlJTyJXsPK&index=23
'Win32 API > 기초' 카테고리의 다른 글
Win32 API 기초 : Collider (1) (4) | 2024.07.20 |
---|---|
Win32 API 기초 : Resource Manager (0) | 2024.07.19 |
Win32 API 기초 : Path Manager (2) | 2024.07.14 |
Win32 API 기초 : Resource (1) (0) | 2024.07.13 |
Win32 API 기초 : 기초 수학 (2) (0) | 2024.07.10 |