이미지 파일을 가져오기 위해서
CTexture 클래스로 객체를 만들고
해당 객체의 멤버 m_hBit가 비트맵을 가리킵니다.
여기서 가리킨다는 의미는 포인터로써 가리킨다는 것이 아닙니다.
비트맵은 윈도우에서 제공하는 오브젝트이기 때문에
해당 오브젝트의 ID를 알고 있어야 해당 오브젝트를 관리할 수 있게 되죠?
m_hBit는 비트맵의 ID를 알고 있다, 저장하고 있다고 보면 됩니다.
그리고 DC 하나를 만들어서 비트맵과 연결하고
그 연결된 DC의 ID를 m_hdc에 저장하여
비트맵에 그리기 작업을 진행할 수 있게 됩니다.
이때 m_hBit가 가리키는 비트맵은 바로,
불러오고자 하는 이미지 파일입니다.
이를 위해서 불러오고 싶은 이미지 파일의 경로를 알아야겠죠.
CTexture 클래스에서
11번째 줄에 있는 Lord 함수가 이 역할을 해 줄 겁니다.
문자열 하나를 참조하여 인자로 받습니다.
Lord 함수의 정의를 살펴보면
LoadImage라는 매크로를 사용했습니다.
인자로 받은 경로에 존재하는 비트맵 파일을 로드하기 위해서죠.
첫 번째 인자로 nullptr을 줍니다.
두 번째 인자로 _strPath의 c_str() 함수의 반환값을
넘겨주고 있습니다. wstring 클래스에는 c_str라는 멤버 함수가
존재하는데 이는 문자열의 내용을 C 스타일의 null로 종료되는
문자열로 변환하는 함수라고 하네요. 즉 wstring형 문자열을
wchar형 포인터로 가리키기 위해 변환해 주는 겁니다.
세 번째 인자는 로드할 이미지의 형식을 지정해 주는 것인데,
비트맵 이미지를 로드할 것이므로 IMAGE_BITMAP를 넘깁니다.
4 ~ 5번째 인자는 리소스의 높이와 너비를 지정하는 부분인데
각각 0 , 0으로 넘겨주면 높이와 너비가 리소스 크기에 맞게
설정됩니다.
6번째 인자를 통해 로드할 이미지에 옵션을 줄 수 있습니다.
기본적인 옵션인 LR_CREATEDIBSECTION과 LR_LOADFROMFILE을
OR( | ) 연산하여 넘겨주겠습니다.
OR 연산이므로 두 비트들을 비교하여
한 쪽이라도 1이면 1이 되어 결과적으로
비트가 1인 부분이 모두 합쳐지게 될 겁니다.
이후 LoadImage 매크로가 반환하는 핸들을
HBITMAP으로 형변환하여 m_hBit에 저장합니다.
이러면 m_hBit는 로드한 비트맵을 가리키게 되겠죠.
20번째 줄에서 assert 매크로가 사용됩니다.
assert 매크로는 괄호 안에 조건이
false면 경고 창을 띄우고 프로그램을 종료시키죠.
m_hBit이 0이면, 즉 비트맵 이미지가 제대로 로딩되지
않았다면 경고 창을 띄우고 프로그램을 종료하게 됩니다.
리소스는 아래 그림처럼 관리할 것입니다.
Output 폴더가 있고 그 안에는
bin, bin_Debug 폴더가 있습니다.
솔루션 구성을 Release로 하여
솔루션 빌드를 진행하면 bin 폴더에 솔루션 파일이 생성되고
솔루션 구성을 Debug로 하여
솔루션 빌드를 진행하면 bin_Debug 폴더에 솔루션 파일이 생성되죠.
이렇게 하려면
솔루션 탐색기에서 프로젝트를
우클릭하여 속성에 들어간 후,
일반에서 '출력 디렉터리'를 수정해야 합니다.
구성을 Release로 설정하고
출력 디렉터리를 위 사진처럼 수정하면
솔루션 경로( SolutionDir )에 Output 폴더 속
bin 폴더에 솔루션 파일이 생성되죠.
이때 SolutionDir를 통해 솔루션 폴더가
어디에 있든 경로를 알아내 인식하기 때문에
그 부분은 직접 입력해 주지 않아도 됩니다.
아래 사진은
구성이 Debug일 때입니다.
bin_Debug 폴더에 솔루션 파일이 생성되겠죠.
CTexture 클래스는 Texture가 있는 폴더 속 경로만 갖고 있습니다.
위 그림에서 texture 폴더부터 그 안에 존재하는
비트맵 파일까지의 경로만 알고 있는 것이죠.
즉 상대 경로만 알고 있습니다.
이것만으로는 리소스를 로드할 수 없습니다.
결국 절대 경로를 완성시켜야, 즉 Texture 위에 존재하는 상위 폴더들의
경로를 모두 알아야 리소스를 제대로 찾아갈 수 있죠.
이를 위해서 존재하는 것이 CPathMgr 클래스입니다.
해당 클래스로 만든 객체는 싱글톤 객체로
프로그램 내에서 유일하게 하나만 존재하는
경로 매니저 객체입니다.
멤버 m_szContentPath는 리소스가 모인 폴더의
경로를 저장합니다. 길이를 255로 제한하겠습니다.
윈도우에서 제공하는 경로의 길이는 최대 255자이기 때문이죠.
12번째 줄에 있는 GetContentPath 함수는
m_szContentPath를 반환하는 함수로
m_szContentPath에 저장된 경로가
수정되면 안되기 때문에 반환형 앞에
const 키워드를 붙였습니다.
초기화 함수인 init 함수의 정의를 살펴보겠습니다.
18번째 줄에 있는 GetCurrentDirectory 매크로는
현재 실행되는 프로그램이 존재하는 경로를
두 번째 인자로 받은 변수에 저장합니다.
첫 번째 인자는 해당 변수에 크기를 의미하죠.
Release로 실행했다면 bin 폴더까지의 경로가,
Debug로 실행했다면 bin_Debug 폴더까지의 경로가
m_szContentPath에 저장되겠죠.
그리고 배열 m_szContentPath의 크기를 iLen에 저장합니다.
23번째 줄에 있는 for 문을 통해 m_szContentPath에 저장된
문자열, 즉 경로를 뒤쪽부터 확인합니다. 그러다가 해당 인덱스에
저장된 문자가 '\\'라면 그곳을 NULL 문자로 바꾸고 for 문을 빠져나옵니다.
문자열에서 bin 또는 bin_Debug 앞에 있는 '\\'가
NULL 문자가 되어 문자열의 끝으로 인식하게 되어
bin 또는 bin_Debug 부분을 없는 취급하게 됩니다.
이렇게 해서 bin 또는 bin_Debug 폴더의
바로 상위 폴더까지의 경로만 남기게 되는 것이죠.
상위 폴더까지의 경로만 남기는 이유는
모든 리소스는 bin 폴더 속 content 폴더에
넣어놓을 것이기 때문에 Release로 실행하든,
Debug로 실행하든 항상 bin 폴더 속 content 폴더의
경로를 알아내야 합니다.
그래서 일단 솔루션 파일이 생성되는 폴더의
상위 폴더인 Output 폴더로 나간 후에
bin 폴더 속 content 폴더로 접근하는 것이죠.
for 문을 통해 Output 폴더로 나가는 것까지 했다면
32번째 줄에 있는 wcscat_s 함수를 통해
m_szContentPath에 저장된 Output 폴더까지의 경로에
\\bin\\content\\를 이어 붙입니다.
m_szContentPath에 content 폴더까지의 경로가
잘 저장되었는지 확인하기 위해 SetWindowText 매크로를
통해 윈도우 창의 타이틀 부분에 m_szContentPath의 값을
출력해 봅니다.
근데 막상 실행하여 윈도우 창의 타이틀 부분을 보면
아마 Output 폴더 쪽 경로가 아닌 프로젝트 경로가
출력될 겁니다.
이유는 Debug로 실행하게 되면
프로그램 자체가 실행된 게 아니라
비주얼 스튜디오가 먼저 실행되고
비주얼 스튜디오를 통해 Debug 모드로
프로그램이 실행되기 때문에
해당 프로젝트 경로를 현재 디렉터리로
인식하게 되는 겁니다.
프로젝트 경로에는 bin 폴더가 존재하지
않으니 제대로 작동하지 않겠죠.
Debug 모드로 작업을 해서 오류가 없는 것을
확인하고 빌드 후 배포를 진행해야 하는데
제대로 작동하지 않으면 곤란합니다.
이를 해결하기 위해서는
솔루션 탐색기에서 프로젝트를 우클릭하여
디버깅에서 '작업 디렉터리' 부분을 위 사진과
같이 솔루션 경로(SolutionDir)에 존재하는
Output 폴더 속 bin 폴더로 수정해야 합니다.
이때 구성은 모든 구성으로 설정해 주어야 합니다.
Start 씬에 로드한 이미지를 출력하기 위해서
CScene_Start 클래스의 소스 파일에서
Start 씬이 시작될 때의 환경을 설정해 주는
Enter 함수의 정의 부분에 코드를 추가했습니다.
공간을 동적 할당하여 CTexture형 객체를 하나 만들고
그 공간을 CTexture형 포인터 tex로 가리킵니다.
지역 변수 strFilepath에 경로 매니저가 갖고 있는
content 폴더까지의 경로를 저장합니다.
그리고 content 폴더까지의 경로에 로드하고자 하는
리소스가 속한 폴더부터 파일까지의 경로를
이어 붙입니다.
이를 Lord 함수의 인자로 넘겨주면
CTexture형 객체는 비트맵 파일을
m_hBit로 가리키고 DC를 하나 만들어
비트맵과 DC를 연결합니다.
이렇게 연결한 DC를
m_hdc가 가리키게 되죠.
이후 메인 윈도우에 해당 비트맵이
다 그려진 후에는 메모리에 존재하는
비트맵을 delete 키워드를 통해
제거해 줍니다.
이때 CTexture형 객체가 delete를 통해
메모리 해제되었기 때문에
CTexture 클래스의 소멸자가 호출될 겁니다.
CTexture 클래스의 소멸자가 해주어야 할 것은
DeleteDC 함수와 DeleteObject 함수를 통해
m_hdc와 m_hBit가 가리키는 DC, 비트맵을
제거해 주는 것입니다.
강의 출처 : https://www.youtube.com/watch?v=0z94ronsynE
'Win32 API > 기초' 카테고리의 다른 글
Win32 API 기초 : Resource Manager (0) | 2024.07.19 |
---|---|
Win32 API 기초 : Resource (2) (0) | 2024.07.18 |
Win32 API 기초 : Resource (1) (0) | 2024.07.13 |
Win32 API 기초 : 기초 수학 (2) (0) | 2024.07.10 |
Win32 API 기초 : 기초 수학 (1) (0) | 2024.07.09 |