?지피껨 만들기.. (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 |