이번 포스트에서는 stb 라이브러리를 대체하기 위해 추가한 BMP 로더에 대해 설명한다. stb_image를 사용해 이미지를 로드하는 기능을 직접 구현함으로써 라이브러리 의존성을 제거했다. 여기서 BMP 파일을 로드하고 처리하는 LoadWithBmp() 함수가 이번에 추가된 부분이다.
BMP 로더 핵심 로직
BMP 파일 로딩은 기존 stb_image를 사용한 로딩 방식과 다르게 직접 바이너리 데이터를 읽어와 이미지의 정보를 추출하고, 이를 m_data 버퍼에 저장하는 과정을 거친다. 자세한 로직은 다음과 같다.
bool Image::LoadWithBmp(const std::string& filepath) {
std::ifstream file(filepath, std::ios::binary);
if (!file) {
std::cerr << "Failed to open BMP file: " << filepath << std::endl;
return false;
}
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
// 파일 헤더 읽기
file.read(reinterpret_cast<char*>(&fileHeader), sizeof(fileHeader));
if (fileHeader.fileType != 0x4D42) { // "BM"인지 확인
std::cerr << "Invalid BMP file: " << filepath << std::endl;
return false;
}
// 정보 헤더 읽기
file.read(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));
if (infoHeader.bitsPerPixel != 24 && infoHeader.bitsPerPixel != 32) {
std::cerr << "Unsupported BMP bit depth: " << infoHeader.bitsPerPixel << std::endl;
return false;
}
// 이미지 크기 및 채널 수 설정
m_width = infoHeader.width;
m_height = abs(infoHeader.height); // BMP 높이는 음수일 수 있음
m_channelCount = infoHeader.bitsPerPixel / 8;
// 이미지 데이터에 대한 메모리 할당
m_data = (uint8_t*)malloc(m_width * m_height * m_channelCount);
if (!m_data) {
std::cerr << "Failed to allocate memory for BMP image" << std::endl;
return false;
}
// 파일 커서를 픽셀 데이터 위치로 이동
file.seekg(fileHeader.dataOffset, file.beg);
// 픽셀 데이터를 행 단위로 읽기 (BMP 데이터는 기본적으로 아래에서 위로 저장됨)
int rowSize = (m_width * m_channelCount + 3) & ~3; // 행의 크기를 4바이트 경계로 맞춤
std::unique_ptr<uint8_t[]> rowData(new uint8_t[rowSize]);
for (int y = 0; y < m_height; ++y) {
file.read(reinterpret_cast<char*>(rowData.get()), rowSize);
memcpy(m_data + y * m_width * m_channelCount, rowData.get(), m_width * m_channelCount);
}
// BGR을 RGB로 변환
if (m_channelCount >= 3) {
for (int i = 0; i < m_width * m_height; ++i) {
uint8_t* pixel = m_data + i * m_channelCount;
std::swap(pixel[0], pixel[2]); // R과 B 스왑
}
}
return true;
}
함수 상세 설명
- 파일 읽기 및 헤더 파싱:
BMP 파일을 바이너리로 열어BMPFileHeader와BMPInfoHeader를 파싱한다. 파일 타입이 "BM"이 아닌 경우나 지원하지 않는 비트 깊이(24비트, 32비트 이외)를 가진 경우 로딩을 실패하도록 설정했다. - 이미지 데이터 메모리 할당:
m_width,m_height,m_channelCount를 헤더에서 가져와 이미지를 저장할 메모리를 할당한다. - 픽셀 데이터 읽기:
BMP 파일의 데이터 오프셋에 해당하는 위치로 커서를 이동시킨 후, 이미지 데이터를 행 단위로 읽어들인다. BMP 파일은 하단부터 상단으로 데이터를 저장하기 때문에, 각 행을 읽은 후m_data버퍼에 순서대로 복사한다. - RGB 변환:
BMP 파일은 기본적으로 BGR 형식이므로, 이미지 채널이 3개 이상일 경우 R과 B 채널을 교환하여 RGB로 변환한다.

문제점 및 향후 계획
현재 과제에서 사용되는 오브젝트의 중심축이 치우쳐 있어 모델이 정확하게 회전하지 않는 문제가 있다. 이는 오브젝트의 중심을 모델의 중심축으로 맞춰야 하는데, 이를 수정하는 것이 우선 과제다.
또한, 이제 더 이상 필요하지 않은 stb와 assimp 라이브러리를 완전히 제거하고 관련 코드를 정리한 후, 정상적으로 작동하는지 검증하는 작업이 남아있다. 마지막으로, 최적화와 코드 리팩토링을 통해 sAssimp 라이브러리와 BMP 로더의 완성도를 높여 나갈 예정이다.
'Computer Graphics > SCOP' 카테고리의 다른 글
| SCOP - 7. 평가 피드백 (0) | 2024.10.09 |
|---|---|
| SCOP - 6. glm 대체하는 sglm 만들기 (0) | 2024.10.04 |
| SCOP - 4. assimp 대체 라이브러리 만들기 (1) (0) | 2024.09.29 |
| SCOP - 3. assimp 대체 라이브러리 만들기 (0) (0) | 2024.09.29 |
| SCOP - 2. 랜덤한 vertex 색 적용 및 texture 적용 (0) | 2024.09.25 |