본문 바로가기

DEV life/DEV.mobile

2D 프레임버퍼의 제어

주위에서 관련 질문을 해주신 분이 계셔서... 이전에 포스팅했던 내용을 보여드릴랬더니만, 일전에 포스트가 단체로 안드로메다 사생대회 가는 바람에 다 지워진 모양입니다.

이왕 포스트 하는 김에, 추가로 몇개 더 턱턱 붙여서 올립니다. 이전처럼 자세한 설명은 시간관계상 생략하겠습니다.-_-;; 코드의 세련미, 효율성이나 가독성은 여기서는 고려치 않았습니다.

##화면의 확대
: 화면을 주어진 배율로 확대합니다. 이 때 배율은 1, 2, ..., n 등 정수 뿐만 아니라, x1.2, x1.8, x2.7 등 실수배도 가능토록 합니다. 입력될 배율의 표현은 두개의 정수[int zoom_mul, int zoom_div]로 받겠습니다.

rate = mul / div;

void *frameBuffer;  //#### pointer of frame Buffer
void *destBuffer;   //#### copy of frame Buffer

//#### zoom rate = int zoom_mul / int zoom_div, zoom_div != 0
//#### scrWidth = width of screen
//#### scrHeight = width of screen

//#### Make destBuffer that will contains cropped frameBuffer
//#### ===============================
//#### 현재 frameBuffer의 중앙으로부터, 확대되어 화면에 뿌려질 부분만을 cropping 합니다.

const int DESTBUFFER_START_X_OFFSET
= (scrWidth * zoom_mul / zoom_div - scrWidth) / (2 * zoom_mul / zoom_div);
const int DESTBUFFER_START_Y_OFFSET 
= (scrHeight * zoom_mul / zoom_div - scrHeight) / (2 * zoom_mul / zoom_div);
const int DESTBUFFER_WIDTH = scrWidth * zoom_div / zoom_mul;
const int DESTBUFFER_HEIGHT = scrHeight * zoom_div / zoom_mul;

int offset = 0;
for ( int j = DESTBUFFER_START_Y_OFFSET; 
           j < DESTBUFFER_START_Y_OFFSET + DESTBUFFER_HEIGHT; j ++)
{
for ( int i = DESTBUFFER_START_X_OFFSET;
           i < DESTBUFFER_START_X_OFFSET + DESTBUFFER_WIDTH ; i ++)
{
*(destBuffer + offset ++) = *(frameBuffer + j * scrWidth + i);
}
}

//#### Make destBuffer fit to frameBuffer
for (j = 0; j < scrHeight; j ++)
{
int _j = j * zoom_div / zoom_mul;

for (i = 0; i < scrWidth; i ++)
{
int _i = i * zoom_div / zoom_mul;

*(frameBuffer + j * scrWidth + i) 
= *(destBuffer + _j * DESTBUFFER_WIDTH + _i);
}
}

* 화면을 확대할 때, 원래 배율 화면1에서 확대된 배율 화면 2로 바로 넘어가지 말고, 중간에 한두 프레임정도 화면1과 화면2를 적절한 알파값으로 겹쳐 그리는 것을 삽입하면 적절한 ZOOMING 연출이 됩니다.


## 전체 화면 BLUR 효과
: 현재 frameBuffer를 알파 적용해서 기준 화면에서 x, y 각각의 방향으로 -1, +1 씩 어긋나게 겹쳐 찍습니다. 타겟 디바이스의 퍼포먼스를 고려해서, 얼마나 많이 겹쳐 찍을 것인지-보통 상하좌우 4번이면 적당하지 않을 까요- 또한 그에 따라 겹쳐 찍을 때 알파 값을 어느 정도로 줄 것인지 그래픽 아티스트와 게임 디자이너 등과 조정하면 될 것입니다. 이 소스를 구구절절히 쓰는 것은 패킷의 낭비와도 같으므로 생략합니다.ㅎㅎ


## 전체 화면 모자이크 효과
: 화면을 정해진 크기[int  mosaic_size]의 격자로 나누어, 정해진 정도[int mosaic_degree]로 평균값을 구해서 칠합니다. 이 때, 각 격자 안의 픽셀들의 평균값을 구하는 방식은 여러가지가 있을 수 있는데요, 역시 타겟 디바이스의 퍼포먼스 등을 고려해서 얼마나 디테일하게 평균값을 구할 것인가를 정해야할 것입니다. 

다만, 특정인의 신원을 보호하기 위해, 혹은 성인물 윤리위원회의 심의를 통과하기 위해-_- 모자이크를 하지 않는다면, 모자이크라는 표현 자체가 '원래 이미지를 얼마나 근접하게 재현하는 가' 하는 것은 쥐한테 삽 들려주는 것만큼 가치가 없는 짓거리라는 것은 분명합니다. 

여기서는 격자의 최 좌측 상단의 점부터 시작하여 최 우측 하단의 점까지 mosaic_degree 만큼의 픽셀 값을 읽어 평균을 내도록 합니다.

void *frameBuffer;  //#### pointer of frame Buffer
void *destBuffer;   //#### copy of frame Buffer

//#### int mosaic_size;
//#### int mosaic_degree;
//#### scrWidth = width of screen
//#### scrHeight = width of screen

//#### void BlendPixel( int bg_RGB, int fg_RGB, int alpha );
//#### int getCoordDivByDeg(int mosaic_size, int mosaic_degree, int step);

for (int j = 0; j < scrHeight / mosaic_size; j++)
{
int _j = j * mosaic_size;

for (int i = 0; i < scrWidth / mosaic_size; i ++)
{
int _i = i * mosaic_size;

int rgbValue = *(destBuffer + _j * scrWidth + _i);

//#### Calculate balanced rgb value for the mosaic square
for (int k = 0; k < mosaic_degree; k ++)
{
int currLoc
    = getCoordDivByDeg(mosaic_size, mosaic_degree, k);
int currRGB 
     = *(frameBuffer + (_j + currLoc) * W + _i +  currLoc);
rgbValue 
     = BlendPixel ( 
           rgbValue, currRGB, 256 - 256 / mosaic_degree);
}
*(destBuffer + j * (scrWidth / mosaic_size)  + i) = rgbValue;
}
}

//#### draw
for (int j = 0; j < scrHeight; j ++)
{
int _j = j / mosaic_size;
for (int i = 0; i < scrWidth; i ++)
*(frameBuffer + j * scrWidth + i) 
     = *(destBuffer + _j * (scrWidth / mosaic_size) + i / mosaic_size);
}


##화면의 회전
: 사실 이것을 구현하는 것이 가장 골치 아팠는데, 제가 아는 삼각함수 이론으로 구현하니 한 8% 부족하더군요-_-;; (잘돌다가 갑자기 쿠에르보 더블 턴을 하더군요...) 그래서 다른 멋쟁이 개발자의 소스를 그냥 날로 먹겠습니다 차용해서 구현했습니다. 쎼쎼 아리가또 땡큐.

void *frameBuffer;  //#### pointer of frame Buffer
void *destBuffer;   //#### copy of frame Buffer

//#### int pivotX;
//#### int pivotY;
//#### int angle;
//#### scrWidth = width of screen
//#### scrHeight = width of screen

//#### return value of sin(int angle), cos(int angle) => -0xFF ~ 0xFF

for (int j = 0; j < scrHeight; j ++)
{
int tmpY = j - pivotY;

for (int i = 0; i < scrWidth; i ++)
{
int tmpX = i - pivotX;

int _i = pivotX + (tmpX * cos(angle) - tmpY * sin(angle) >> 8);
int _j = pivotY + (tmpX * sin(angle) + tmpY * cos(angle) >> 8);

if (_i >= scrWidth || _i < 0) continue;
if (_j >= scrHeight || _j < 0) continue;

*(frameBuffer + j * scrWidth + i) = *(destBuffer + _j * scrWidth + _i);
}
}


'DEV life > DEV.mobile' 카테고리의 다른 글

날로 먹는 iPhone dev 일기 #3  (2) 2009.05.06
SKT의 앱스토어, 성공할까?  (26) 2009.04.14
날로 먹는 iPhone dev 일기 #2  (0) 2009.04.07
날로 먹는 iPhone dev 일기 #1  (2) 2009.04.01
날로 먹는 iPhone dev 일기 #0  (2) 2009.03.30