[GpGiki 대문으로]

지피껨 만들기 06


?지피껨 만들기.. (6)

 샬롬...
 예, 덥습니다.
 덥죠.
 덥다!!!!!!!!!!! -_-
 요새 더위 때문에 죽을 맛입니다.
 덥다보니 본업에 충실하기 어렵고...
 기분 전환으로 또 글을 쓰게... 됐습니다. 쿨럭...
 원래 6편에서 조성현군(http://lapage.2ing.net)의 테트리스를
 GP32로 포팅(?)하는 걸 다루려고 했었는데...
 그렇게까지 하면 이 더위에 정신이 돌아나갈 것 같고....
 그건 7편으로 잠시 미루고..
 여기서는 간단한 녀석들만 다루도록 하죠.
 어떤 내용들일까요...
 미리 내용을 말하고 시작을 하려고 했는데..
 왠지 재미가 없을 것... 같네요.
 그냥... 넘어가죠 -_-

8. 16bit color 이미지 출력 !!!!

 예, 뭐.. 그런... 겁니다.
 VC++ 쓰시는 분들이야 "이걸 왜 다루냐!"라고 하시겠지만...
 gcc로 작업하시는 분들은 요놈 때문에 좀 약이 오르죠.
 일단, 소스나 뿌려보죠 -_-

#include "gpdef.h"
#include "gpgraphic.h"

int GpBitBlt16( GPDRAWTAG *gptag, GPDRAWSURFACE *ptgpds, int dx, int dy, int width, int height,
				unsigned char * src, int sx, int sy,int imgw, int imgh )
{
	uword *video = (uword*)ptgpds->ptbuffer;
	uword *target, *source;
	int xx, yy, i;

	if( dx < 0 )	{ sx = -dx;	dx += sx; }
	if( dy < 0 )	{ sy = -dy; dy += sy; }

	if( dx + width > ptgpds->buf_w )	width  -= ( dx + width )  - ptgpds->buf_w  + 1;
	if( dy + height > ptgpds->buf_h )	height -= ( dy + height ) - ptgpds->buf_h + 1;

	xx = width  - sx + 1;
	yy = height - sy + 1;

	target = video       + dx * ptgpds->buf_h + ptgpds->buf_h - ( dy + yy - 1 ) + 1;
	source = (uword*)src + sx * imgh          + imgh          - ( sy + yy - 1 ) + 1;

	for( i = 0 ; i < xx ; i++ )
	{
		gm_memcpy( target, source, yy * 2 );
		target += ptgpds->buf_h;
		source += imgh;
	}
}

int GpTransBlt16( GPDRAWTAG *gptag, GPDRAWSURFACE *ptgpds, int dx, int dy, int width, int height,
				unsigned char * src, int sx, int sy,int imgw, int imgh, int color )
{
	uword *video = (uword*)ptgpds->ptbuffer;
	uword *target, *source;
	int xx, yy, i, j;
	uword data;

	if( dx < 0 )	{ sx = -dx;	dx += sx; }
	if( dy < 0 )	{ sy = -dy; dy += sy; }

	if( dx + width > ptgpds->buf_w )	width  -= ( dx + width )  - ptgpds->buf_w  + 1;
	if( dy + height > ptgpds->buf_h )	height -= ( dy + height ) - ptgpds->buf_h + 1;

	xx = width  - sx + 1;
	yy = height - sy + 1;

	target = video       + dx * ptgpds->buf_h + ptgpds->buf_h - ( dy + yy - 1 ) + 1;
	source = (uword*)src + sx * imgh          + imgh          - ( sy + yy - 1 ) + 1;

	for( i = 0 ; i < xx ; i++ )
	{
		for( j = 0 ; j < yy ; j++ )
		{
			data = source[j];
			if( data != color )	target[j] = data;
		}
	}
}
 최적화라든지 뭐 그런 건 전혀 고려가 안 되어 있구요..
 실제로 똑같이 작동한다고 보장할 수는 없습니다.
 단지, 현재 16bit color로 작업 중인 녀석을 이걸로 바로 컴파일할 수 있죠.
 특별히 설명...을 하는 건 좀 어렵다고 생각이 들구요... -_-
 아래 for문이 실제로 이미지를 출력하는 부분이고..
 그 위는 Clipping( 화면 밖으로 나가는 이미지를 잘라냄 )을 처리하는 부분이죠.
 예, 그런... 겁니다. ^^
 자세한 내용은 DOS 시절의 자료를... (탕)
 뭐, 더우니까.... 대충 대충 넘어가죠 -_-
 나중에 좀 날씨가 추워지면(언제냐!) 구체적으로 설명할지도... 쿨럭...

9. 16bit color에서 반투명 효과

 자, 일단 16bit color에서 요놈이 어떻게 되있는지 알아보죠.
 RGB값이 5:5:5:1의 구조로 되어있습니다.
 무슨 소리냐면... 앞의 5bit가 Red, 5bit가 Green, 5bit가 Blue, 1bit는 꽝!인 거죠.
 그럼, 그 컬러에서 RGB 값을 뽑아내는 매크로를 좀 만들어 보죠.

#define COLOR_R( c ) ( ( (c) >> 11 ) & 0x1F ) #define COLOR_G( c ) ( ( (c) >> 6 ) & 0x1F ) #define COLOR_B( c ) ( ( (c) >> 1 ) & 0x1F )

 간단 하죠? +_+
 자, 그럼 이제 반투명 효과를 주도록 합시다.
 뭐, 특별한 건 안 할 꺼고..
 대화창 같은 거 방투명으로 띄우는 그짓을 해보죠.
 즉, 반투명 사각형을 그리는 거죠. ^^
 일단, 일반 사각형을 그리는 것부터 만들어 보죠.
 ( 16bit color 함수 없으니까 이짓...을 하는군요 -_- )
void draw_box( int x, int y, int w, int h, int color )
{
	uword *video = (uword*)gpDraw[nflip].ptbuffer;
	uword *target;
	int i, j;

	for( i = 0 ; i < w ; i++ )
	{
		target = video + ( x + i ) * LCD_HEIGHT + LCD_HEIGHT - ( y + h - 1 ) - 1;
		for( j = 0 ; j < h ; j++ )	*target++ = color;
	}
}
 간단하죠?
 최적화는 안 하냐, target을 구하는데 왜 매번 곱하기를 해서 삽질하냐.. 클리핑은 안 하냐...
 그렇게 물으실 수도 있는데........
 더운데 그냥 넘어가죠 -_-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 하여튼.. 여기서 반투명으로 만드는 건 간단합니다.

void draw_box_alpha( int x, int y, int w, int h, int color, int alpha )
{
	uword *video = (uword*)gpDraw[nflip].ptbuffer;
	uword *target = video + x * LCD_HEIGHT + LCD_HEIGHT - ( y + h - 1 ) - 1;
	ubyte r, g, b;
	int beta = 100 - alpha;
	int i, j;

	for( i = 0 ; i < w ; i++ )
	{
		for( j = 0 ; j < h ; j++ )
		{
			r = COLOR_R( color ) * alpha / 100 + COLOR_R( *target ) * beta / 100;
			g = COLOR_G( color ) * alpha / 100 + COLOR_G( *target ) * beta / 100;
			b = COLOR_B( color ) * alpha / 100 + COLOR_B( *target ) * beta / 100;
			*target++ = ( r << 11 ) | ( g << 6 ) | ( b << 1 );
		}
		target += LCD_HEIGHT - h;
	}
}
 여기서 alpha는 % 단위입니다.
 float로 줘서 해도 되는데... 3D하는 것도 아니고 -_-
 %보다 낮으면 티도 안난다는 -_- ( RGB가 각각 32단계 밖에 안되는데.. )
 헉, 그런데... 이건 왜 위에꺼보다 최적화가 되어있지...
 ( 작업 중인 소스를 들고 왔기 때문에... 이런 일이.. 일어나는 겁니다 -_- )
 위에 있는 draw_box도 이런 식으로 해주면...
 for( i = ..... )쪽에서 target을 구하기 위해 곱하기를 계속 안 해도 되는 겁니다.
 이.. 이런식으로 최적화를 조금씩 하는 거죠. 쿨럭..... -_-
 좀 더 최적화를 하고 싶으시면 alpha를 2의 승수로 처리를 해서
 / 100이 아니라 쉬프트 연산으로 끝장낼 수도 있겠죠...
 하여튼... 그게 중요한 게 아니라....
 소스는 간단합니다.

섞인 색 = 찍으려는 색 * alpha / 100 + 원래 있던 색 * ( 100 - alpha ) / 100

 이 색 섞는 원리(?)에 입각해서 그냥 섞어주는 거죠. ^^
 RGB를 가지고 16bit color를 만들어 내는 건

( r << 11 ) | ( g << 6 ) | ( b << 1 )

 이렇게...
 ( 이건 전에 팔레트 세팅 때도 본 거 같죠? ^^ )
 자, 대충대충 넘어갑시다! 더우니까!! +_+

10. 16bit color에서 문자 출력

 뭐, 또 gcc 사용자를 위한 건데..
 꼭 그런 건 아니죠.
 자신의 폰트로 출력하고 싶을 때 ( 물론 폰트 세팅이 따로 있긴 하지만 -_- )
 또는 폰트 출력에 좀 더 효과를 주고 싶을 때...
 그럴 때 참고..하세요.
 일단은.... 완성형 한글을 쓰는데...
 확장 완성형은 다루지 않을 꺼고..
 좀 묘하게 나오는 녀석들도 있을 겁니다.
 ( 개인적으로는 작업 중에는 완성형을 쓰고
   마지막에는 조합형으로 모두 옮길 생각이라.... )
 하여튼.. 그렇다고 치고..
 소스나 뿌려보죠.

ubyte HANFONT[2350][32];
ubyte ENGFONT[256][16];

void load_font( char *han, char *eng )
{
	F_HANDLE fh;
	ulong rcount;

	GpFileOpen( han, OPEN_R, &fh );
	GpFileRead( fh, HANFONT, 2350 * 32, &rcount );
	GpFileClose( fh );

	GpFileOpen( eng, OPEN_R, &fh );
	GpFileRead( fh, ENGFONT, 256 * 16, &rcount );
	GpFileClose( fh );
}

void put_eng_font( int x, int y, ubyte *font, uword color )
{
	int i;
	uword *video = (uword*)gpDraw[nflip].ptbuffer + x * LCD_HEIGHT + LCD_HEIGHT - y - 1;

	for( i = 0 ; i < 16 ; i++ )
	{
		if( *font )
		{
			if( *font & 0x80 )	*video                      = color;
			if( *font & 0x40 )	*( video + LCD_HEIGHT     ) = color;
			if( *font & 0x20 )	*( video + LCD_HEIGHT * 2 ) = color;
			if( *font & 0x10 )	*( video + LCD_HEIGHT * 3 ) = color;
			if( *font & 0x08 )	*( video + LCD_HEIGHT * 4 ) = color;
			if( *font & 0x04 )	*( video + LCD_HEIGHT * 5 ) = color;
			if( *font & 0x02 )	*( video + LCD_HEIGHT * 6 ) = color;
			if( *font & 0x01 )	*( video + LCD_HEIGHT * 7 ) = color;
		}
		video--;
		font++;
	}
}

void put_han_font( int x, int y, ubyte *font, uword color )
{
	int i;
	uword *video = (uword*)gpDraw[nflip].ptbuffer + x * LCD_HEIGHT + LCD_HEIGHT - y - 1;

	for( i = 0 ; i < 16 ; i++ )
	{
		if( *font )
		{
			if( *font & 0x80 )	*video                      = color;
			if( *font & 0x40 )	*( video + LCD_HEIGHT     ) = color;
			if( *font & 0x20 )	*( video + LCD_HEIGHT * 2 ) = color;
			if( *font & 0x10 )	*( video + LCD_HEIGHT * 3 ) = color;
			if( *font & 0x08 )	*( video + LCD_HEIGHT * 4 ) = color;
			if( *font & 0x04 )	*( video + LCD_HEIGHT * 5 ) = color;
			if( *font & 0x02 )	*( video + LCD_HEIGHT * 6 ) = color;
			if( *font & 0x01 )	*( video + LCD_HEIGHT * 7 ) = color;
		}
		video += LCD_HEIGHT * 8;
		font++;
		if( *font )
		{
			if( *font & 0x80 )	*video                      = color;
			if( *font & 0x40 )	*( video + LCD_HEIGHT     ) = color;
			if( *font & 0x20 )	*( video + LCD_HEIGHT * 2 ) = color;
			if( *font & 0x10 )	*( video + LCD_HEIGHT * 3 ) = color;
			if( *font & 0x08 )	*( video + LCD_HEIGHT * 4 ) = color;
			if( *font & 0x04 )	*( video + LCD_HEIGHT * 5 ) = color;
			if( *font & 0x02 )	*( video + LCD_HEIGHT * 6 ) = color;
			if( *font & 0x01 )	*( video + LCD_HEIGHT * 7 ) = color;
		}
		video -= LCD_HEIGHT * 8;
		video--;
		font++;
	}
}

void hputs( int x, int y, uword color, char *s )
{
	int i;
	ubyte data, data2;
	int index;

	for( i = 0 ; i < strlen( s ) ; i++ )
	{
		data = s[i];

		if( data & 0x80 )
		{
			data2 = s[++i];
			index = ( data - 0xB0 ) * 94 + data2 - 0xA1;
			put_han_font( x, y, HANFONT[index], color );
			x += 16;
		}
		else
		{
			put_eng_font( x, y, ENGFONT[data], color );
			x += 8;
		}
	}
}

 한글은 최상위비트가 켜지는 거고...
 뭐, 한글 관련 이야기는 다른 문서를 참고를.. (탕)
 예, 대충 대충 넘어가죠. 더우니까 -_-
 포인트는 폰트 출력하는 부분인데...
 폰트 데이터를 화면에 뿌려주는 방법을 다루고 있죠. 뭐.. ^^
 ( 개인적으론 비트맵 데이터라고 부르는데 헷갈릴까봐 이렇게 표기합니다 )
 자, 여기서 조금 장난을 칠 수도 있겠죠?
 개인적으로 8bit color를 사용할 때 쓰던 방법인데..
 대개는 팔레트를 그라데이션이 가능하게 만들죠.
 즉, 이런 짓을 하면 어떨까요?


void put_eng_font( int x, int y, ubyte *font, uword color )
{
	int i;
	ubyte *video = (ubyte*)gpDraw[nflip].ptbuffer + x * LCD_HEIGHT + LCD_HEIGHT - y - 1;

	for( i = 0 ; i < 16 ; i++ )
	{
		if( *font )
		{
			if( *font & 0x80 )	*video                      = color;
			if( *font & 0x40 )	*( video + LCD_HEIGHT     ) = color;
			if( *font & 0x20 )	*( video + LCD_HEIGHT * 2 ) = color;
			if( *font & 0x10 )	*( video + LCD_HEIGHT * 3 ) = color;
			if( *font & 0x08 )	*( video + LCD_HEIGHT * 4 ) = color;
			if( *font & 0x04 )	*( video + LCD_HEIGHT * 5 ) = color;
			if( *font & 0x02 )	*( video + LCD_HEIGHT * 6 ) = color;
			if( *font & 0x01 )	*( video + LCD_HEIGHT * 7 ) = color;
		}
		video--;
		font++;
		color++;
	}
}

 color을 그라데이션 첫번째 단계의 색으로 주면 멋지게 16단계 그라데이션이 먹죠.
 자, 8단계짜리 그라데이션이라면..


void put_eng_font( int x, int y, ubyte *font, uword color )
{
	int i;
	ubyte *video = (ubyte*)gpDraw[nflip].ptbuffer + x * LCD_HEIGHT + LCD_HEIGHT - y - 1;

	for( i = 0 ; i < 16 ; i++ )
	{
		if( *font )
		{
			if( *font & 0x80 )	*video                      = color;
			if( *font & 0x40 )	*( video + LCD_HEIGHT     ) = color;
			if( *font & 0x20 )	*( video + LCD_HEIGHT * 2 ) = color;
			if( *font & 0x10 )	*( video + LCD_HEIGHT * 3 ) = color;
			if( *font & 0x08 )	*( video + LCD_HEIGHT * 4 ) = color;
			if( *font & 0x04 )	*( video + LCD_HEIGHT * 5 ) = color;
			if( *font & 0x02 )	*( video + LCD_HEIGHT * 6 ) = color;
			if( *font & 0x01 )	*( video + LCD_HEIGHT * 7 ) = color;
		}
		video--;
		font++;
		if( i < 6 )	color++;
		else		color--;
	}
}

 이런 것도 되겠죠?
 이외에도 대각선으로 흐르게 할 수도 있고..
 뭐, 여러가지가 있는데..
 연구하시면 얼마든지 나오죠.
 16bit color로 하실 경우에는 RGB가 그대로 드러나기 때문에..
 정말 연구만 하면 무슨 삽질이든지 할 수 있죠.
 ( 개인적으로는... 그냥 한 색으로 미는 걸 좋아하긴 합니다 -_- )

11. 8bit color에서 반투명 처리

 아아, 이건... 미리 만들어 둔 소스..가 없네요 -_-
 일단, 그렇다고 치고...
 뭐, 하면서 만들어내죠 -_-
 일단, 8bit color의 경우엔 RGB에 바로 접근이 불가능하기 때문에
 미리 테이블을 만들어 두죠.
 물론, 팔레트를 이용하니까 팔레트를 이용해서 RGB에 접근해도 되는데..
 문제는 컬러->RGB는 쉬운데, RGB->컬러가 어려워서...
 테이블을 이용...하는 겁니다. ^^;;;;;
 자, 어떤 테이블을 만드느냐.. 바로 이거죠.

ubyte alpha_table[256];

 무슨 소리냐면...
 한 밝기를 50% 정도로 줄어들게 하는 ( 즉, 컬러는 black, alpha가 50% )
 그런 효과를 내고 싶다면..
 alpha_table[0]에는 0번 컬러의 50% 밝기의 색에 해당하는
 컬러값을 넣는 거죠.
 ( 아아, 무슨 소린지 내가 봐도 모르겠다. )
 즉, 컬러 테이블을 만드는 소스를 뿌려보고 생각해 보죠 -_-
 ( 후후후, 메모장에서 즉석으로 하는 거니까... 버그 있어도 전 모른다는 -_- )


void make_alpha_table( int color, int alpha )
{
	int i, j, d;
	int r, g, b;
	int beta = 100 - alpha;
	int min, alpha_color;

	for( i = 0 ; i < 256 ; i++ )
	{
		r = palette[color * 3    ] * alpha / 100 + palette[i * 3    ] * beta / 100;
		g = palette[color * 3 + 1] * alpha / 100 + palette[i * 3 + 1] * beta / 100;
		b = palette[color * 3 + 2] * alpha / 100 + palette[i * 3 + 2] * beta / 100;

		min = 10000;
		for( j = 0 ; j < 256 ; j++ )
		{
			d  = abs( palette[j * 3    ] - r );
			d += abs( palette[j * 3 + 1] - g );
			d += abs( palette[j * 3 + 1] - b );
			if( d < min )
			{
				alpha_color = j;
				min = d;
			}
		}

		alpha_table[i] = alpha_color;
	}
}

 일단, 섞은 색을 구해서.. 팔레트를 뒤져서 가장 비슷한 책을 찾는 거죠.
 예... 그런 겁니다.
 이걸 이용해서 화면에 출력하는 짓을 하려면...


void draw_box_alpha( int x, int y, int w, int h )
{
	ubyte *video = (uword*)gpDraw[nflip].ptbuffer;
	ubyte *target = video + x * LCD_HEIGHT + LCD_HEIGHT - ( y + h - 1 ) - 1;
	ubyte r, g, b;
	int beta = 100 - alpha;
	int i, j;

	for( i = 0 ; i < w ; i++ )
	{
		for( j = 0 ; j < h ; j++ )	*target = alpha_table[*target];
		target += LCD_HEIGHT - h;
	}
}

 이런 거죠. 뭐... ^^;;;;;;;
 이건 미리 계산된 것만 가능한 게 단점인데..
 테이블을 좀 여러개 만들면 좀 더 다양하게 쓸 수 있긴 하죠.
 하여튼... 16bit color보다 떨어지는 건 확실합니다 +_+
 이런 방법 외에도 팔레트를 통일을 시켜서 ( 예를 들어 16단계 )
 그 단계 안에서 떨어뜨리는 방법이 있구요...
 ( 물론, 밝기 조절... 정도 수준 밖에.... )
 또는 동일 단계의 다른 색으로 옮겨서 밝기는 무관하고 한 색으로 변환되는
 그런 느낌을 줄 수도 있죠.
 ( "부서져라 A 버튼"에서 사용할 예정인 방법...입니다. )
 뭐, DOS 시절...로 돌아가보면 온갖 뽀록과 편법이 난무하니...
 그 시절로 돌아가 머리를 굴려보는 것도 좋...겠죠. ^^
 아아, 덥습니다... -_-
 이번에는 초 극강 날림이네요.
 그냥... 그런가보다...하고 넘어가 주시길... -_-;;;;
 위의 16bit 관련 소스는 제 홈피에 올려놨구요. ( gp_ex08.zip )
 뭐.. 그런 겁니다.
 그리고, #gp32dev 채널에 좀 많이 들어와 주세요~!!!!!!!
 모두 IRC를 실행하시고!!!!!
 irc.hanchat.org로 접속하셔서.......
 /join #gp32dev를 때려주세요!!!!!!!!!!!!!!!!!!!!!!!
 모두모두 재미있게 놀자구요 -_-
 mIRC 같은 게 없다구요?
 귀찮다구요?
 http://www.hanirc.net/hanchat/?chan=gp32dev&server=irc.hanirc.org
 이 URL로 들어오시면 바로 있습니다!!!!!!!!!!
 자, 들어오세요!!!!!!!!!!!!! 우오오오오!!!!!!!!!!!!!!!
 아, 글구....
 GP32 개발자 오프를 가지자는데...
 자자자... 그것도 한번 이야기를 나눠봅시다 +_+
 그런.. 것입니다.
 다음에는 뭐를 다룰까..
 특별한 예정이 없으면 테트리스로 일단... 가겠습니다.
 요구하시는 부분이 있다면..
 그걸 다루도록...하지요.
 오늘도 즐거운 하루!!!! (탕)

2002.06.08 아샬


지피껨 만들기로 돌아가기


제일 위로
최종 수정 일시: 01월 12일(2006년) 05:27 PM 편집 | 정보 | 차이 | 비슷한 페이지 DebugInfo
유용한 페이지들: 분류 분류 | 자유로운 연습장 SandBox | 무작위 페이지들 RandomPages | 인기있는 페이지들 MostPopular