사실 위의 15bit 그림 그리는건 게임의 OP, ED, Title, Event 그림 이외엔 전혀
쓸모가 없다고 생각합니다
. 게다가 H/W 제한상(SDK 제한도 있습니다)
15bit
그림을 위아래 화면 동시 띄우는것이 힘듭니다
.

2화면 동시에 그리고 하드웨어적인 속도를 보장받기 위해 256컬러를 사용합니다.
256
컬러 이하는 24bit구조와 차이점이 있고, 우리가 필요로 하는 데이터는 아래
그림과 같습니다
.

사용자 삽입 이미지

위의 구조에서 중요한건 팔레트 데이터 입니다.
팔레트 데이터를 위의 24bit RGB 15bit RGB 다운 시킨 것처럼 비트 다운
시켜 주면 됩니다.


#define RGB15(r,g,b) (u16)(r|g<<5|b<<10) // RGB 15bit 변환 컬러

여기서, 팔레트 데이터가 흰색~검은색 까지 모든 색상의 대표색 256개가 지정된 것이 아니고
, 그림에서 사용하는 대표적인 256색만 사용합니다.

DS
에서 256BG를 띄우는데 3가지 데이터가 필요합니다.

Data

역 할

자료형

픽셀(타일)데이터

해당픽셀에 어떤색이 들어가는지 가르키는 값

u8

팔레트 데이터

이 그림에서 사용하는 색

u16

맵 데이터

위의 그림을 타일로 쪼개서 중복을 최대한 피하는 data

u16

 

각각 데이터에 따른 설명으로

Data

설 명

픽셀(타일)데이터

PC BMP파일의 픽셀 데이터를 그대로 옮기되, 출력을 8x8 tile형식으로 맞춰서 u8 데이터 형식, unsigned char 형식으로 맞춰야 합니다

팔레트 데이터

PC BMP파일의 팔레트 데이터를 옮겨오되, 위에서 설명했듯, NDS 최대 컬러수인 RGB15bit를 맞추기 위해 원래 24bit 팔레트 컬러를 각각 3bit bit down 시켜 줍니다

맵 데이터

사용자 삽입 이미지


NDS그림 H/W 그림 처리 방식은 독특한 방식으로 되어있습니다



위 그림은 NDS에서 그림처리를 하는 방식을 보여주는 극단적인 예라 할 수 있습니다. 격자모양의 사각형이 1개의 타일입니다.
맨 좌측 상단부터 1tile로 들어가며, 256x192 그림의 경우 32x24 타일로 구성이 됩니다
.
타일 구성의 이유는 위 그림에서 보듯 선택된 영역

(
노란, 청색 테두리 타일)이 단 2Tile로 처리가 가능하기에 별 다른 알고리즘 없이 압축효과를 볼 수 있습니다
그리고 이 맵 데이터를 조작함으로서 그림 스크롤 및 여러 효과를 나타내는것이 가능합니다.

 

타일 개념이 생소한 개념이므로 좀더 추가 설명을 하겠습니다.


사용자 삽입 이미지

위의 모자이크 같은 부분(64x64픽셀) Data 형식

extern const u8 sp_data[4096] = {

//Tile number 0

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,

 

//Tile number 1

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,

0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
//
이하 중략

//Tile number 62

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,

 

//Tile number 63

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,

 

};

 

위의 Data소스 sp_data[x]는 그림 픽셀 좌표입니다.
Tile number의 픽셀 Data 뭉치는 PC BMP파일로 따지면 1Line 입니다.
(
그림이
64x64)
하지만 NDS의 그림 로드는 위의 소스처럼, 8x8의 한 타일을 먼저 찍고,
그 다음 옆으로 이동하는 것을 알 수 있습니다.

 

 

BG를 띄우는 순서는
1. VRAM 초기화
2. BG올라갈 VRAM 할당
3. 해당 메모리 번지로 그림 픽셀 데이터 올림
4. 팔레트 데이터 올림
5. 픽셀 데이터를 조합해서 만드는 맵 파일을 올림
6. 출력될 BG 선택
   - 여려 효과 등은 BG2,3에서 지원

기서 투명색에 관해서 입니다. 투명색은 0번 팔레트를 사용합니다.
, 256컬러를 사용하기 보다는 투명색을 염두해서 255컬러를 사용하는 것이 현명하다고 생각합니다
.

포토샵등 툴에서 이런 제약을 가할 수 있으므로 그래픽 처리할 때 이점을 주의하는 것이 좋다고 생각합니다

Sub 출력은 Main LCD와 크게 다를것이 없습니다.
하지만 최대 128KB(VRAM_C) 만 할당이 가능하고,
(MAIN LCD
VRAM_ ABCD, 512KB 가능
)
약간 함수명이 다를뿐 크게 차이가 있지 않습니다.

NDS에서 지원하는 최대 컬러로 그림을 그리는 방법입니다.
이 방법은
퀄리티를 추구하고, 사용방식이 DX draw 개념처럼 사용할 수 있지만, 단점으로 OAM과 동시에 사용하기가 힘듭니다. 그리고 속도도 느린편이고 VRAM 차지하는 용량도 많습니다
.

15bit
의 그림을 만들기 위해서는 포토샵 등에서는 지원이 안되고, 따로 툴을 제작해서 컨버팅을 시켜야 합니다
. (이와 관련 툴은 컨버팅 툴 포스트로..)

그전에 BMP파일 구조에 대해서 약간 생각해보면, 우선 24bit 컬러의 경우 파일 구조는 아래
와 같은 구조로 구성되어 있습니다.

사용자 삽입 이미지

각각의 Pixel data RGB 각각 8bit (총합 24bit)구성 되어 있으니,
RGB를 각각 5bit(총합
15bit) RGB값을 3bit씩 다운시켜 주면 됩니다.

위 방식을 근거로 파일 변환을 시킨 바이너리 파일을 이하 bin이라 하고,
이 파일을 읽기 위해 작업을 해야 합니다
.

NDS
에서 15bit 그림을 올릴 땐 2가지 방법이 동원됩니다
.

1. 직접 그리기

Nitro SDK에서 제공하는 인터페이스인
 
Memory Interface _ Direct Memory Access Copy(32bit)
방식으로 하는 방법.

이 함수를 사용하면 아주 간단하게 이미지를 뿌릴 수 있습니다

 

2. 프레임 버퍼 변수 사용하기
프레임 버퍼 변수를 사용하면 VRAM의 공간 제약이 사라집니다.
물론 NDS SDK H/W 지원이 안되고, 속도가 느려지는 단점이 있습니다
.
하지만 Direct Draw surface같은 개념이기 떄문에,
DX Draw
사용자는 쉽게 적응 됩니다
.

프레임 버퍼는

void* FrameBuffer = (u16*)(HW_LCDC_VRAM_A);
와 같이 선언하며, VRAM_A( VRAM 첫부분)를 포인터로 가르키는 뜻입니다.

화면을 2차원의 사각형 배열로 생각하지 않고, 1차원 메모리 차원으로 생각해야 하므로
수학공식을 잘 생각 및 활용해야 합니다.

그림 찍는 방법은 아래와 같은 함수로 생각할 수 있으며, 아래 함수의 경우, 투명색을 처리해줍니다
당연히 투명색을 찍고 싶지 않을땐, Trans_rgb 값을 NULL로 해주면 됩니다.

투명색을 빼고 그리는 함수

void Image_Class::TransparBlt(u32 Frame_Start_x, u32 Frame_Start_y,   
  
//
프레임 x,y좌표
   u32 Blt_Image_x, u32 Blt_Image_y,           
   
//
복사할 이미지 x,y좌표

                              u32 Blt_Width, u32 Blt_Height, u16 
                              Trans_rgb) //
복사그림 가로,세로,투명색

 {

u32 posY, posX;

int bitX, bitY;

RECT r;

u16 PrintPixel;

                          

r.left = Frame_Start_x;

r.top = Frame_Start_y;

r.buttom = Frame_Start_y + Blt_Height;

r.right = Frame_Start_x + Blt_Width;

 

for(posY = r.top, bitY = 0; posY < r.buttom ; ++posY, ++bitY)

{                         

            for(posX = r.left, bitX = 0; posX < r.right ; ++posX, ++bitX)

            {

               PrintPixel = m_pBmp[(bitY+Blt_Image_y) *  
                                  (m_iBmpWidth) + (bitX+Blt_Image_x)];

                 if(Trans_rgb != PrintPixel)

                   m_pFrameBuff[posY*(SCR_WIDTH) + posX] = PrintPixel;

            }                                                   
}

}

위의 함수는 2 for문을 돌면서, 해당위치에 점을 대입해서 찍는 방식.

장점으로는 저 프레임 버퍼를 DX Draw Real Serface라 생각, 넣어주면

DX Draw 처럼 구현이 됩니다.

하지만, 256BG와 비교하였을시, 1/6 ~ 1/2 정도 속도가 느려집니다.
(
실제 NDS상에서는 속도는 그림2개 정도 띄울 때 평범하다 싶을 정도 속도가 나옵니다.)


위의 2방법으로 그림을 메모리에 올린 후에는 현제 화면에 뜰 Video RAM이 어느 RAM 지역인지 알려줘야 합니다.

참고로 Sub화면에 15bit 그림을 그릴려면 Main LCD 와 Sub LCD의 화면을 바꿔주는 함수를 따로 추가 시켜야 합니다.


 

NDS의 이미지 처리를 앞서 하드웨어 제원을 살펴보겠습니다.

3인치 2LCD, 256x192 해상도를 가지고 있으며, 색상컬러는 RGB 각각 2^5를 할당하는 15bit체계를 사용합니다.

H/W 제약상, LCD에서 3D가 나오면 다른 한곳은 2D가 나옵니다.

NDS의 그래픽 처리 방식에 대해서 이야기 하겠습니다.

NDS
의 메모리는 Main Memory 4MB, 비디오 메모리 640Kbyte로 구성되어있습니다.


요즘 PC의 최소 메모리 등급인 128MB에 비하면, 정말 엄청 적은 메모리입니다
.

이 메모리도 한 LCD에서 사용하는 것이 아니라 2LCD에서 나눠서 사용합니다
.


언뜻, 640Kb 2로 나눠서 1LCD 320Kb를 배정해서 프로그래밍 해야 한다고

생각할 수 있지만
,

실상, NDS의 게임을 자세히 보시면, 플레이어가 집중하는 LCD는 화려한데에 비해,
 
단순히 정보 제공 능력만
하는 LCD(보통 터치 스크린있는 하단 LCD)는 간단한
 
그림으로 채워져 있습니다
.

, 플레이어가 2LCD를 동시에 집중해서 플레이하는건 어려우니 한개의 LCD에만

리소스를 집중하는 방식입니다
.


이에 H/W적으로 NDS에서 VRAM 구성은 아래와 같은 식으로 되어있습니다.


사용자 삽입 이미지

하지만, LCD 1곳에 BG 4개를 겹처서 Main LCD에 그리게 할려면 (참조 : New Super Mario brothers가 그런 구조입니다)
256x192(
화면 해상도) = 49152(Byte) x 4( BG) = 196608(Byte) => 196Kbyte가 필요하게 됩니다
. 물론 이것은 무압축 모드이고, 압축하면 128KB 이하로 가능합니다.
(그림이 단순하면 단순할수록 압축효과는 좋아집니다. 자세한건 BG 설명 포스트로)

현제 BMP Converter Tool 에서는 무압축 모드만 지원하므로, 위의 최대 그림크기를 가정하면,  VRAM_A(128KB)으로는 들어가지 않으므로, HW_LCD_VRAM_AB(256Kbyte)와 같은 구조를 사용합니다
.

, 이와 같은 여러 제약으로 NDS 게임을 제작할 때 가장 먼저 고려할 것이 그래픽이라 생각합니다.

그래픽은, 가급적, 256Color을 사용하며, 화면 크기도 LCD최대 해상도인 256x192이지만
, 전체적으로 512x512해상도의 그림까지는 메모리에 올릴 수 있습니다.

256Color를 사용하기 때문에 배경은 단조롭게,
OAM
은 한가지 컬러 계통으로 디자인해야 한다고 생각합니다
.

사용자 삽입 이미지
(에밀크로니클 온라인의 몬스터(시나몬)의 디자인. 갈색 컬러 계통의 예)

이제 프로그래밍 순차적으로 접근하겠습니다.

1. VRAM을 어디까지 할당 하는 것에 관해 초기화 시켜야 합니다
2.  각각 사용에 맞게 초기화 함수를 사용해야 합니다
.

여기선 공통적으로 2진 파일을 읽어서 NDS에 출력하게 할것입니다
.

3. NDS 파티션은 NDS FTA 구조를 사용하며, DOS FTA16과 그 기능은 흡사한거 같습니다. 하지만, 여러 보안 솔루션(복사 방지 및 아마추어 DS 제작 라이브러리 제한)등을 두고 있습니다.

4. 파일 로드할 준비가 되었고, 2진 파일로 된 그림을 불러오면 됩니다.

이후 여기에 올릴 NDS상 그림을 띄우는 방법에 대해서 입니다.

NDS 그림 종류

장점

제한 사항

15Bit 컬러 그림

Direct Draw 개념

Main LCD만 출력

256BG

NDS 2D H/W Engine 지원

팔레트상 256, 16 색만 가능

OAM

NDS 2D H/W Engine 지원

스프라이트개념, 1 LCD 128개 배치 가능

위와 같은 종류가 있으며 하나 하나 기술하겠습니다.



[1] OAM (Object Attract Memory) : NDS에서 일종의 스프라이트 처리를 할 때 사용하는 개념입니다.

명칭- NDS

LCD- 듀얼액정+터치패널
3인치+3인치

해상도
256x192xRGBx2   -> GBA에서 가로로 16픽셀 세로로 32픽셀 늘어났습니다

표시능력-
32,768색        2^15 (R, G, B 각각 5bit 씩)

CPU-
ARM946E-S(67MHz)
+ARM7TDMI(33MHz)

메인 메모리 4MB
ARM9 /ARM7 공용 32KB
ARM7 전용 내부 워크RAM 64KB
VRAM 656KB

사운드-               
16ch ADPCM/PCM 마이크 입력
(최대 8ch를 PSG에)

MEDIA-
카트리지+카트리지

2D 그래픽
 BG:4면 OBJ:128개

3D 그래픽 좌표변화
최대4M 정점/초

폴리곤 묘화
최대 120K 폴리곤/초

픽셀 묘화 능력
최대 30M 픽셀/초

출처 : http://cafe.naver.com/gbastation/329

+ Recent posts