2015년 5월 24일 일요일

더블버퍼링

mfc의 경우에 onDraw나 onPaint에 그림을 그리거나 
혹은 비트맵등의 이미지 파일을 호출할 텐데 처음 윈도우프로그래밍을 배우는
사람들이라면 api를 쓰던지 뭘 하던지 많은 이미지를 여러번 호출하거나
그리게되면 자주 화면 깜빡거림을 보게되어 거슬린다고 짜증내게 될 것이다.

그 이유는 반복문으로 한 그림을 여러번 그린다고 가정했을때를 예를 들겠다.

onDraw나 onPaint에 그냥 CDC와 BITMAP를 생성해서
바닥과 벽이라는 이미지를 33픽셀 단위로 그린다고 하였을때


//셋팅된 맵 배열 읽고 이미지 삽입
for (int x = 0; x < 1279; x += 33){
for (int y = 0; y < 719; y += 33){
if (mainRoop->cMap[mainRoop->
                                    player->playerMapCount].mapSet[x][y] == 0){
//벽
pDC->BitBlt(x, y, 33, 33, &wallDC, 0, 0, SRCCOPY);
}
else{
//바닥
pDC->BitBlt(x, y, 33, 33, &floorDC, 0, 0, SRCCOPY);
}
}
}

이 코드는 몇번 그리게 되고 그럼 몇번이나 깜빡일까?
Sleep를 걸어보면 알겠지만 이미지한번 그릴때마다 깜빡일것이다.
물론 이렇게 한번 쫙 그리고 그만둔다면 OnEraseBkgnd 함수를 찾아서
리턴값을 수정하면 하얗게 깜빡이는 현상이 사라지겠지만 게임같은 경우는
맵외에도 몬스터도 실시간으로 움직일텐데 그냥 onDraw나 onPaint에 다 그리면
매우 심각하게 반짝인다. 한번 그릴때마다 갱신하니까 장난아니게 되는것이다.
실 예로 영상을 첨부하겠다.
영상을 보면 알겠지만 깜빡임이 장난 아닐것이다. 맵 비트맵 33픽셀단위로 한번씩 그리고 다 그린다음에는 각 몬스터를 그리고 플레이어를 그리고.. 게임이니까 움직일때마다 다시 그려야하므로 깜빡임이 맵그리기, 몬스터 각각 이미지 뿌리기, 플레이어 뿌리기 하면 와우..

하지만 걱정말자 해결 방법이 있다.

예를 조금 더 들어보겠다.
화가가 그림을 그리는건 직접 실시간으로 볼 수 있다. 어디가 그려지는지, 
무엇을 지우는지 실시간으로 관찰이 가능하고 눈에 보인다.
그러나 카메라는 기기에서 모두 처리하고 한번에 출력해버린다.

즉 더블버퍼링이라는 것은 카메라 처럼 뒤에서 모두 그린뒤 한번에 
onDraw나 onPaint에 그림을 그려주는것이다.

어느 프로그래밍을 하던지 개념은 같다. 그러니 코드가 다르더라도 개념만 이해하면
api던 mfc건 뭐건 그냥 적용이 가능하니 나는 그냥 mfc로 설명하겠다.



void CGameProjectView::OnDraw(CDC* pDC){

//화면 크기와 그릴 공간을 담당할 rect
CRect rect;
GetClientRect(&rect);

// 메모리 DC 선언
CDC dubleBfDC;

CBitmap bitmap;
CBitmap* pOldBitmap;
// 화면 DC와 호환되는 메모리 DC 객체를 생성
dubleBfDC.CreateCompatibleDC(pDC);

// 화면 DC와 호환되는 Bitmap 생성
bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());

pOldBitmap = memDC.SelectObject(&bitmap);

//현재 화면 해상도를 가져와서 검은색으로 모두 채움
dubleBfDC.PatBlt(0, 0, rect.Width(), rect.Height(), BLACKNESS);


//이미지셋 함수에 파라메터값으로 &dubleBfDC를 넘김
ImageSet(&dubleBfDC);

// 메모리 DC를 화면 DC에 고속 복사
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &dubleBfDC, 0, 0, SRCCOPY);

dubleBfDC.SelectObject(pOldBitmap);
dubleBfDC.DeleteDC();
bitmap.DeleteObject();

}

void CGameProjectView::ImageSet(CDC* pDC){
// onDraw나 onPaint에 그렸던 것을 여기다가 옮겨준다.
}

/*소스코드 참고 : http://warmz.tistory.com/865 */

코드를 보면 onDraw에서 dubleBfDC를 생성해서 뒤에서 그림 그릴 도화지를 생성했다.
그 다음 ImageSet에서 그림을 모두 dubleBfDC에 그린다음 onDraw에서는 다 그려진
dubleBfDC를 출력한다.

카메라처럼 뒤에서 모두 이미지를 그린다음 출력만 onDraw에서 하는것이다.
그렇게 하면 깜빡임이 거의 없다고 보면된다.
아래 영상은 더블버퍼링을 사용한 영상이다.

댓글 없음:

댓글 쓰기