요즘 자주 듣는 노래~




< 출처 : 아셔 <- 이 가수 >

요즘 자주 듣는 노래^^;

'하루 지껄이기' 카테고리의 다른 글

아프다.  (0) 2004.05.05
안좋다...  (0) 2004.05.04
체육대회..  (0) 2004.05.04
요즘 하는 일!!  (0) 2004.04.28
블로그가 모지?  (0) 2004.04.28
칼루
하루 지껄이기 2004. 5. 1. 20:03
,

1.PlayStation 1(one) 2D Format 해부학 - TimFormat을 읽자

Html 안되나..-_-;; 이건 2004년 4월 4일날 쓴거다.

원래 저번주 주말에 3편을 썼어야 하는데, 자격증 시험이다 모다해서 일요일날 바뻐서 쓸수가 없었다;;


사실 2틀 뒤에 소풍날이여서 그때 쓰려고 했지만...또 대회다 모다해서 소풍을 못갔다..(그 덕에 졸업사진 촬영을 못함 ㅡ_ㅡ)


블로그에선 "책갈피" 를 못쓰는군요 ㅜ_ㅜ html이 안되성...


어쨌든 강좌 본문 시작~~

========================= 여 기 서 부 터 ===========================


Tim Format을 읽자

작성자 : kallru(신휘재)
kallru@hanmail.net
pkallru@gmail.com

※이 문서는 아무 곳에나 배포해도 되지만, 출처(작성자)는 반드시 기재해 주시기 바라며,
이 문서를 아무 곳에 배포해서 생기는 모든 일에 책임은 배포자에게 있음을 알립니다.

 

- 목  차 -

1.머리말

2.TimFormat이란?

3.용어

4.TimFormat의 헤더

5.TimFormat읽기 (C/C++/API)



1. 머리말
약 1주일간 tim 파일을 접하면서 이 포맷에 대한 정보가 무척 부족하다고 느꼈다. 해외에는 비교적 PlayStation1에 자국화가 활발하지만, 국내에는 아직 초급단계라 생각되고, 또 모든 정보가 해외로부터 얻고 있는 형편이다. 이번 기회에 tim 포맷을 분석하면서 내가 실수했던 부분부터 실질적인 프로그래밍까지, 내 힘이 닿는 부분까지 상세하게 기술하려 한다. 나 다음에 사람, 그 다음에 사람....앞으로 국내 PlayStation1 자국화에 뛰어들 사람들이 나와 같은 실수를 범하지 않기 위한 참고자료가 되기를 바라며 시작하겠다.
덧붙여 나는 글제주가 없기 때문에 매끄럽지 않더라도 이해해주길 바란다.


2. Tim Format 이란?
나도 이것에 대해 자세히 알지 못한다. 다만 PlayStation1에 2D 그래픽 파일이라는 것뿐..
PlayStation1에서 사용되는 2D 포맷이므로 자국화에 꼭 필요한 Font는 대부분 이 포맷으로 되어 있다. 압축 여부는 아직 잘 모르겠고, 한가지 확실한 건 2D 포맷이라는 것뿐..^^;


3.용어
이 문서에서 사용될 전문용어들이다. 모르는 부분이 나오거나 할 때에는 꼭 한번씩 용어를 확인해보자. 나 또한 아직 헷갈리는 것들이 있다.
Header(헤더) - 이런 기초적인 것까지 용어 집에 넣으면 너무 분량이 많아지지 않을까 생각되지만, 이 헤더라는 것은 중요해서 넣게 되었다. 헤더라는 것은 보통 어떤 format 이든간에 다 만들어 둔다. 앞으로 나올 파일, 이 포맷에 대한 전체적인 정보를 담고 있다. 그림 포맷으로 예를 들면 Width(가로) Height(세로)는 몇이고, Bit는 몇 비트를 쓰고 있는지, 그 외에 필요한 정보들을 모아서 하나에 구조체를 형성해두는데, 이것이 Header헤더가 되는 것이다.

CLUT - 컬러 참조 테이블 (Color LookUp Tble, 팔레트에 대한 소니측의 용어)

Image Org - 이미지의 시작 좌표를 설정하는 것이다. TIM 파일을 플레이스테이션
의 VRAM에서 사용할 때 쓰는 것입니다. 고치는 작업에서는 특별히 필요하지 않지만
TIM 이미지와 헤더를 생성하는 프로그램에서는 유용할 것입니다.

Paltte Org - CLUT 데이터의 시작 좌표를 설정하는 것입니다. 고치는 입장에서는
특별히 필요하지 않지만 TIM 이미지와 헤더를 생성하는 프로그램에는 유용할 것입
니다.

BPP: 픽셀당 비트 수 (Pixels per bit)


4.Tim Format의 Header(헤더)
- Header -
:: 기본적인 헤더, 사이즈는 8바이트이다
[Signature] 4 Bytes : TIM 형식이라는 것을 알리는 ID Tag
- 0x10
- 0x00
- 0x00
- 0x00
[BPP Mode] 1 Byte : 그래픽 모드를 정의한다.
- 0x08 signifies 4bpp,
- 0x09 signifies 8bpp,
- 0x02 signifies 16 bpp,
- 0x03 signifies 24 bpp mode.
[Reserved] 3 Bytes : 예약이라는 것인데, bmp 포맷도 그렇고 쓰지 않는다. -_-
- 0x00
- 0x00
- 0x00


- Palette Info -
:: 12+ Bytes : 팔레트 정보인데 팔레트 헤더가 12 Byte 이며 CLUTData가 + 되어 진다.
즉 CLUTData가 200Byte 라면 총 212 Byte가 되는 것이다.

[Length of the CLUT Data] 4 Bytes : 이것은 CLUT데이터+12 한 전체 크기이다.
CLUTData공식 : CLUT안에 색깔의 수*CLUTs의 수*2+0xC
[Palette Org X] 2 Bytes : X coordinate in frame buffer.
[Palette Org Y] 2 Bytes : Y coordinate in frame buffer.
[Number of Colors in CLUT] 2 Bytes : Depends on the BPP Mode.
- The value for 4 bpp is 16, and for 8 bpp is 256.
[Number of CLUTs] 2 Bytes : CLUT의 개수 총 16개 까지 갖을수 있다.

[CLUT Data] : Number of CLUTs * Number of Colors in CLUT * 2
- CLUT의 수 * CLUT안에 색깔의 수 * 2
- CLUT Data는 최대 16개까지 가능 할 것이다. (추측)
- 이것이 + 가 되는 대상인 것이다.


 - Image Info -
:: 12+ Bytes : 이미지 정보, 이미지 헤더(12Byte) + 이미지 데이터

[Length of the Image Data] 4 Bytes : 이미지 헤더(12Byte) + 이미지 데이터, 총 사이즈
- 중요!! : Image Width * 2 * Image Height + 0xC 이것이 실제 이미지 데이터 사이즈

[Image Org X] 2 Bytes : Frame buffer X coordinate.
[Image Org Y] 2 Bytes : Frame buffer Y coordinate.
[Image Width] 2 Bytes : 가로 크기이지만 BPP Mode에 따라서 구하는 계산법이 있다.
[Image Height] 2 Bytes : This is the height of the image in pixels.
[Image Data] Varies : Contains data on all the pixels in the image.


※Image Width 데이터 길이 계산
4,8BPP에서는 아직 잘 모르겠지만, 24BPP에서는 Width에 * 2를 해줘야 Width의 데이터 길이를 얻을 수 있다. 좀 더 쉽게 말해서 우리가 보통 이미지에 데이터 크기를 구할 때 가장 쉽게, 또 많이 사용하는 것이 Width * Height 이다 이것은 초등학교 시절 사각형에 넓이를 구할 때 배웠을 것이다. 하지만 특이하게도 Tim Format은 이렇게 되어 있지 않다. 실제로 이미지 데이터 크기를 얻기 위해선 Width * 2 * Height로 해줘야 한다. 어떤 이유인지는 모르겠지만 분명 저렇게 해야만 값을 얻을 수가 있었다.
[+] 16BPP에서는 Width * 3 (RGB 각각 1Byte를 쓰므로 *3)을 해야만 했다. Width * 2 * 3 이라 생각했던 나는 2틀간 삽질을 통해서 Width * 2는 24BPP에서만 그런 듯 하다. 다만 이것은 BMP로 변환할때에 입장이다. TIM 자체 데이터는 어떻게 되어 있는지 모르겠지만 16Bit를 24Bit로 변환할 때 Width * 3으로 해줘야 함을 잊어서는 안되겠다.
 다만, 아직 4, 8BPP에서도 저렇게 구해야 되는지는 모르겠다. 하지만 나는 이것에 대해서 의심이 없다. 아마 4, 8BPP에서도 2를 곱해줘야 될 것 같다. 그럼 이해를 돕기 위해 간단한 예를 하나 설명하고 다음으로 넘어가겠다.
예) 가로가 100이고 세로가 50인 이미지 파일을 읽어 온다고 가정하자.
프로그램으로 분명
for(i=0; i<Height; i++)
   for(j=0; j<Width; j++)
   {
   }
이런 식으로 for문을 돌리면서 이미지의 데이터를 가저올 것이다. 하지만 Tim에선 이렇게 하면 값을 제대로 얻을 수 없고 다음과 같이 해야 한다.
for(i=0; i<Height; i++)
   for(j=0; j<Width*2; j++)
   {
   }


※Image Width 실제 길이 구하는 계산
이것은 이미지의 가로 길이를 구하는 것이지, 이미지 가로 데이터 길이가 아니다. 데이터 길이를 구하는 식은 따로 위의 식이다. Tim에선 Width가 모드에 따라서 틀린데, 이것도 모드에 따라서 그것이 틀리다.
- 4BPP : Image Width * 4
- 8BPP : Image Width * 2
- 16BPP : Image Width (아무런 계산할 필요가 없다)
- 24BPP : Image Width/1.5
이것은 이미지의 가로길이다. 세로길이는 읽어온 길이가 실제 길이이므로 따로 계산해줄것이 없지만, 가로 길이는 이상하게 되어있다. 이해를 돕기 위해 예를 하나 설명하겠다.

예) 읽어 오려고 하는 Tim파일이 가로가 100이고 세로가 50이다.
그럼 위에 Image Info를 읽어 오면 Image Width 와 Image Height에 이미지 길이가 각각 들어오게 된다. 하지만 이것이 BPP 모드에 따라 길이가 다르다.
실제 길이는 100이지만 현재 BPP가 4BPP라면 분명 Image Width로 넘어온 값은 100이 아니라 100/4인 25로 나올 것이다. 그렇다면 반대로 4BPP 모드에서 실제 Image Width 값을 얻으려면 Image Width * 4를 해서 얻을수 있다. 다시 말해, 가로 길이가 100 짜리 그림은 25라고 헤더에 정의되어 있다. 200짜리 라면 50이라고 되어 있다.


5.Tim Format 읽기
5번 파트에 들어가기 전에 이 문서를 읽는 사람은 어느 정도에 프로그래밍 지식이 있어야 하며, C/C++/윈도우API를 알고 있어야 한다. 이러한 전제 하에 진행되기 때문이다. 또 이곳에서 나오는 코드는 내가 1주일간 분석하며 만들었던 TimVeiw의 실제 코드이므로 복사해서 사용해도 무방하다. 다만 좋지 못한 부분과 간결하지 못한 로직이 다수 존재하므로 이해해 주길 바라며, 이 문서를 보는 사람이 적당하게 바꾸어서 사용하기 바란다.

그럼 이제부터 필요한 구조체를 만들어 보자.
typedef struct
{
 //Tim의 전체적인 헤더
 int  Sinnature; //TIM형식 이라는 것을 알리는 ID
 int  BPPMode; //BppMode와 Reserved -> 각각 1바이트,3바이트 합이 4바이트
}TIMHEADER;
데이터형에 주의해라. int는 윈도우즈에서 4Byte를 할당받으므로 Tim 헤더의 [Signature] 크기를 만족할 수 있다. 그와 마찬가지로 [BPPMode]를 받는데, BPP는 1Byte 이고 뒤에 예약(Reserved)가 3Byte이다. 두 개를 합치면 이것 역시 4Byte가 되므로 int형으로 선언했다.

typedef struct
{
 // - Palette Info -  //
 int CTLength; //Length of the CLUT Data
 short pOrgX;  //Palette Org X
 short pOrgY;  //Palette Org Y
 short ColNum;  //Number of Colors in CLUT
 short Num;  //Number of CLUT
 BYTE *Data;  //CLUT Data : CLUT의 수 * CLUT안에 색깔의 수 * 2
}PALETTEINFO;
Data는 BYTE형으로 1Byte씩 가질수 있도록 선언했다.

typedef struct
{
 int Size;   //이미지 사이즈 : Width * 2 * Height
 int imgLength;  //Length of the Image Data
 short imgOrgX;  //Image Org X
 short imgOrgY;  //Image Org Y
 short Width;   //Image Width
 short Height;   //Image Height
 BYTE *Data;   //Image Data
}IMAGEINFO;

typedef struct
{
 DWORD Size;
 WORD Width;
 WORD Height;
 BYTE *Data;
}IMAGEDATA;
따로 ImageData 구조체를 만들었다. 이것은 내가 필요한 이미지 정보들만 갖는 구조체 이다.

BITMAPFILEHEADER BMPFileHeader;
BITMAPINFOHEADER BMPInfoHeader;

TIMHEADER TIMHeader;
PALETTEINFO PInfo;
IMAGEINFO imgInfo;
IMAGEDATA Image24;

여기까지 필요한 구조체와 변수이다.
이제 실제로 읽어보자

HANDLE Rfpt;   //파일을 읽기 위한 핸들이다.
DWORD RWSize;

Rfpt=CreateFile(FileName,
               GENERIC_READ,0,
               NULL,OPEN_EXISTING,
               FILE_ATTRIBUTE_NORMAL,NULL);
if(Rfpt==INVALID_HANDLE_VALUE)
{
 ::MessageBox(::GetActiveWindow(),FileName,"Error",MB_OK);
 return;
}

//가장 먼저 Sinnature를 읽어서 이 파일이 Tim 파일인지 확인한다.
나는 확인하는 부분을 생략했다.
ReadFile(Rfpt,&TIMHeader.Sinnature,sizeof(int),&RWSize,NULL);
ReadFile(Rfpt,&TIMHeader.BPPMode,sizeof(int),&RWSize,NULL);

//아래 코드는 BPPMode가 0x02(16BPP)와 0x03(24BPP)가 아니라면, 즉 4, 8 이라면
//팔레트 정보를 읽어야 하므로 그 부분에 대한 코드이다.
//4BPP,8BPP는 CLUT가 있다.
if(TIMHeader.BPPMode != 0x02 && //4BPP,8BPP ↓ in Src
 TIMHeader.BPPMode != 0x03) //16BPP,24BPP라면 건너뛴다.
{
 //---- Palette Info Read ------//
 ReadFile(Rfpt,&PInfo.CTLength,4,&RWSize,NULL);
 ReadFile(Rfpt,&PInfo.pOrgX,2,&RWSize,NULL);
 ReadFile(Rfpt,&PInfo.pOrgY,2,&RWSize,NULL);
 ReadFile(Rfpt,&PInfo.ColNum,2,&RWSize,NULL);
 ReadFile(Rfpt,&PInfo.Num,2,&RWSize,NULL);
 
 PInfo.Data = new BYTE[PInfo.Num*PInfo.ColNum*2]; // Size : CLUT수 * CLUT컬러수 * 2  
 ReadFile(Rfpt,PInfo.Data,PInfo.Num*PInfo.ColNum*2,
  &RWSize,NULL); //CLUT Data Read
}
//16BPP,24BPP는 CLUT가 없다 ImageINFO만 가지고 있다.
//------ Image Read ------//
ReadFile(Rfpt,&imgInfo.imgLength,4,&RWSize,NULL);
ReadFile(Rfpt,&imgInfo.imgOrgX,2,&RWSize,NULL);
ReadFile(Rfpt,&imgInfo.imgOrgY,2,&RWSize,NULL);
ReadFile(Rfpt,&imgInfo.Width,2,&RWSize,NULL);
ReadFile(Rfpt,&imgInfo.Height,2,&RWSize,NULL);

//위에서 언급했다시피 실제 Width 데이터 길이를 얻기 위해선 * 2를 해야 한다.
//다시 강조하지만 데이터 길이와, 이미지 길이는 다른것이며, 이미지 길이는 각 BPPMod
 //마다 계산해주는 값이 틀리다.
imgInfo.Size = imgInfo.Width*2*imgInfo.Height;

imgInfo.Data = new BYTE[ imgInfo.Size ];
ZeroMemory(imgInfo.Data, imgInfo.Size);

ReadFile(Rfpt,imgInfo.Data,imgInfo.Size,&RWSize,NULL);
CloseHandle(Rfpt);
}


- 강좌는 여기까지
주석도 적절하게 붙여놨고, 이 문서를 작성하면서 덧붙여 쓴 주석도 있으니 이 소스를 보는데 에는 큰 무리가 없으리라 봅니다 [TimFormat을 읽자]는 여기서 마치도록 하겠습니다.
이것은 1편에 불과합니다. 아직 16비트를 다 하지 못해서.....앞으로 화면 출력에 대해서 잠깐 언급하자면, 제가 선택한 것은 바로 bmp 변환후 출력입니다. 4일 정도 동안 Tim 데이터를 바로 화면에 뿌리기 위해서 Directdraw도 써보았지만 제가 아직 실력이 안 되는 거라 그런지 해답을 찾지 못했습니다. 그래서 bmp로 변환 후에 bmp를 화면에 뿌리던가 하는 방법이 좋을 것 같아서 이 방법으로 나가겠습니다.
 다음부터는 ConvertBMP 강좌를 쓰겠습니다. 아마 이 강좌는 4개, 또는 3개 정도로 나뉘어질 것 같네요. 24BPP, 16BPP, 8BPP, 4BPP로 나누던가 24,16,(8,4) 이렇게 나누던가...어쨌든 이게 시작이니까..그럼 16BPP나 계속 풀어야겠네요.

칼루
나만의 강의 2004. 5. 1. 19:30
,
Powerd by Tistory, designed by criuce
rss