이번 포스트에서는 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 |