2007. 11. 14. 15:26
     

07 NDS 홈브루(Homebrew) - KNG(KKAMAGUI NDS Graphic) File 변환 툴

원문 :  http://kkamagui.springnote.com/pages/566442

 

들어가기 전에...

 

0.버전관리

  • 2007/11/07 23:42:37 : 이미지 변환 시, 마지막 한줄이 빠지는 버그 수정

 

 

0.시작하면서...

 NDS에서 그림을 출력하려면 어떻게 해야할까? 방법은 크게 2가지가 있다.

  1. 이미지를 BYTE 배열 형태로 롬 파일에 삽입하는 방법
  2. libfat를 이용해서 특정 경로에서 직접 읽어 표시하는 방법

 어느 방법을 사용하던지 중요한 점은 NDS에서 편하게 불러쓰고 화면에 뿌릴 수 있어야 한다는 점이다. 그래서 KNG(KKAMAGUI NDS Graphic) 포맷을 개발하게 되었고, RGB555 포맷으로 그대로 변환하여 저장하게 하여 별도의 처리없이 화면에 표시가능하도록 구성했다.

 이제 KNG에 대해서 하나하나 알아보자.

 

1.KNG 구성

 KNG는 RGB555 포맷을 기본으로 사용하도록 만들어졌고 크게 헤더 부분과 데이터 부분, 두부분으로 구성되어있다. 헤더를 굳이 만들 필요가 있는가 하는 사람도 있겠지만, PSP와 같은 기기로 확장을 생각하고 있기 때문에 나름 범용으로 쓰기위해 헤더와 데이터로 구분했다.

 아래는 헤더의 구성이다.

  1. // 매크로 정의
    #define VERSION_NDS_0_0 0x00
  2. #pragma pack( push, 1 )
  3. // 헤더 구조체
    typedef struct kkamaguiNdsGraphicStruct
    {
        char vcSignature[ 3 ]; // KNG 설정
        BYTE bVersion;         // 이미지 포맷 버전, 0x00 설정
        int iWidth;            // 이미지 넓이
        int iHeight;           // 이미지 높이
    } KNG, * PKNG;
  4. #pragma pack( pop )

 

 각 부분의 역할은 아래와 같다.

  • vcSignature : 파일 포맷의 유효성을 검증하기위한 방편
  • bVersion : 다양한 데이터 양식을 지원하기위해 넣은 버전 번호. 매크로에 정의되어있듯 NDS RGB555 포맷은 0x00으로 정의되어있음
  • iWidth : 이미지의 가로 넓이
  • iHeight : 이미지의 세로 넓이

 

 데이터는 헤더의 바로 뒤에 연달아서 나오게 되어있으므로 헤더를 뛰어넘고 데이터를 접근하면 Raw Data에 바로 접근할 수 있다. 데이터 양을 줄이기 위해서는 Run-Length Encoding과 같은 방법을 사용해서 처리하면 사이즈를 줄일 수 있지만, 현재 버전에서는 굳이 넣지 않았다.

 NDS Firmware 문서를 뒤져보면 Firmware에서 Run-Length Decoding과 Huffman Decoding 루틴을 제공하는 것을 알 수 있는데, 사이즈가 부담스러우면 두가지 방법을 사용하는 것도 괜찮은듯 하다.

 

2.KNG 파일 포맷으로 변환

 KNG로 변환하는 것은 아주 간단하다. 헤더를 생성한 다음, RGB 포맷을 RGB555 포맷으로 수정하여 저장하면 끝이다. 첨부에 포함된 변환 프로그램 소스를 보면 쉽게 알 수 있는데, 핵심 부분은 CMyImage 클래스 이다. FreeImage 라이브러리를 사용해서 이미지를 읽고 헤더를 생성한후 RGB555 포맷으로 저장한다. 학교 수업때 사용한 프로젝트를 약간 변경한 소스여서 지저분한데, 마음에 안들면 새로 만들도록 하자.

 아래는 CMyImage 클래스의 간단한 사용법이다.

  1. CMyImage clImage;
  2. ... 생략 ...
  3. clImage.LoadImage( "a.jpg" );
  4. clImage.SaveImageWithConvert();
  5. clImage.UnloadImage();

 위를 실행하고 나면 a.jpg.kng 라는 파일이 a.jpg 파일이 있는 같은 폴더에 생성된다.

 

 변환하는 과정을 좀더 상세히 살펴보자. 어떻게 변경하는 것일까? 아래는 실제 변환하는 소스이다.

  1. /**
        이미지를 변환과 함께 저장한다.
    */
    BOOL CMyImage::SaveImageWithConvert( void )
    {
        CSize clSize;
        int i;
        int j;
        RGBQUAD stRgb;
        char vcNewFileName[ 256 ];
        KNG stHeader;
        int iFd;
        WORD wValue;
        WORD wR;
        WORD wG;
        WORD wB;
       
        // 파일 이름을 설정한다.
        vcNewFileName[ 0 ] = '\0';
        _snprintf( vcNewFileName, sizeof( vcNewFileName ), "%s.kng", m_vcFileName );
  2.     iFd = _open( vcNewFileName, _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY,
            _S_IREAD | _S_IWRITE );
        if( iFd == -1 )
        {
            return FALSE;
        }
  3.     // 헤더를 설정하여 파일에 쓴다.
        SetHeaderInfo( &stHeader );
        _write( iFd, &stHeader, sizeof( stHeader ) );
  4.     // 이미지를 변환해서 파일에 쓴다.
        clSize = GetImageSize();

  5.     // 위 아래가 바뀌어 있어서 뒤집는다.
        for( j = clSize.cy - 1 ; j >= 0 ; j-- )
        {
            for( i = 0 ; i < clSize.cx ; i++ )
            {
                // RGB 값을 얻어서 555 Format으로 맞춘다.
                stRgb = GetPixel( i, j );
               
                wR = ( WORD )( stRgb.rgbRed * ( ( double ) 31 / 255 ) );
                wG = ( WORD )( stRgb.rgbGreen * ( ( double ) 31 / 255 ) );
                wB = ( WORD )( stRgb.rgbBlue * ( ( double ) 31 / 255 ) );
               
                // MSB는 Alpha Bit이다. 이것을 0으로 설정하면 NDS에서 그려지지 않는다.
                wValue = 0x8000 | ( wB << 10 ) | ( wG << 5 ) | ( wR );
                _write( iFd, &wValue, 2 );
                //TRACE( "[%d %d] [%d %d %d] %X\n", i, j, wR, wG, wB, wValue );
            }
        }
        _close( iFd );
  6.     return TRUE;
    }

 파일을 관리하는 부분을 다 제외하고 파란색 부분만 보면, 헤더를 생성하고 이미지의 각 부분의 Pixel 값을 읽은 후 RGB555 포맷에 맞게 곱셈/나눗셈을 해서 처리하는 것을 알 수 있다. 간단한 소스니 별다른 부연 설명은 필요 없을 듯...

 한가지 유의할 점은 원 이미지는 위아래가 뒤집혀서 저장되므로 그것을 바로잡기위해 루프의 인덱스를 조작한 부분이다. 혹시나 특정 파일 포맷을 변환했는데, 위아래가 뒤집혀서 NDS에 출력될 경우는 저 부분을 손보면 된다.

 

3.KNG 이미지 출력

 KNG 이미지를 출력하는 방법은 아주 간단하다. 일단 헤더에서 이미지에 대한 정보를 추출한 다음 루프를 돌면서 화면에 뿌려주면 된다. RGB555 모드로 NDS를 설정하는 방법이 궁금하면 02 NDS 윈도우 시스템(Windows System) 문서를 참고하도록 하자.

 아래는 KNG 파일을 출력하는 소스의 일부분이다.

  1.     // 복사한다.
     for( i = 0 ; i < iHeight; i++ )
     {
         iTemp1 = ( i + iDstY ) * iDstWidth + iDstX;
         iTemp2 = ( i + iSrcY ) * iSrcWidth + iSrcX;
        
         memcpy( pwDstAddr + iTemp1, pwSrcAddr + iTemp2, iWidth * 2 );
     }

 pwDstAddr이 RGB555로 설정된 비디오 메모리의 주소이고, pwSrcAddr이 KNG 파일 내의 Raw Data의 주소이다. 간단히 메모리간의 복사로 해결할 수 있다.

 

4.변환 툴 사용법

 이미지 변환툴은 jpg, png, bmp와 같은 그래픽 파일 포맷을 지원한다. 단 사이즈 조작 기능은 없으니 사이즈를 조작하려면 그림판이나 포토샵을 이용해서 이미 조작해야 할 것이다. 원활한 사용을 위해서는 이미지 크기가 256 X 192 이하로 하는게 좋다. 이 이상된다면 출력 루틴을 수정하고 그래픽 모드 또한 수정해야 할 것이므로, 정신 건강에 매우 해롭다. ㅡ_ㅡa...

 아래는 변환툴을 실행한 화면이다.

KNG1.PNG

<실행화면>

 메뉴의 파일->이미지 파일 선택을 클릭하여 변환할 파일을 선택하거나, 툴바의 열기 버튼을 클릭하여(위의 붉은색) 변환할 파일을 선택하면 이미지 변환이 수행되고 아래와 같은 화면이 표시되면 정상적으로 변환 된 것이다.

KNG2.PNG

<이미지 변환 성공>

 해당 이미지가 있는 폴더에 보면 .kng 확장자가 붙은 파일이 추가로 생성되었음을 알 수 있다. 이 파일을 롬파일에 추가하거나 libfat를 이용해서 불러 사용하면 된다. 롬파일에 이미지 또는 파일을 추가하는 방법은 참고. 롬 파일에 데이터(사운드, 이미지 등등) 파일 포함 방법 문서를 참고하도록 하자.

 

5.마치면서...

 NDS용 파일 포맷을 생성하고 변환하는 방법에 대해서 간단히 알아보았다. 이것으로 홈브루를 더욱 예쁘게 만들 수 있게 되었다. 더욱 홈브루 개발에 정진하자. @0@)/~!!!

 

6.첨부

 

 

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.


Android App

Posted by 호기심 많은 kkamagui(까마귀, 한승훈)

댓글을 달아 주세요