반응형

Double Buffering이란?

Double Buffering이란 화면에 그려지는 내용을 두 개의 버퍼를 사용하여 관리하는 기법이다. 이 기법은 화면을 그릴 때 발생하는 깜빡임 문제를 방지하고, 화면을 부드럽고 자연스럽게 업데이트 하는 데 사용된다. 

 

더블 버퍼링이 필요한 이유

컴퓨터 화면에 무언가를 그릴 때 내용을 화면에 직접 그리게 되면 화면이 깜빡이거나, 그리는 중에 일부만 보일 수 있다. 예를 들어서 테트리스 게임을 만든다고 할 때, 블럭이 이동할 때마다 화면을 새로 그려야 하기 때문에 깜빡임이 생겨 불편할 수 있다. 이 문제를 해결 하기 위해 두개의 버퍼(Buffer)을 사용한다.

 

버퍼란?

버퍼(Buffer)은 임시 데이터 저장소이다. 일시적으로 데이터를 보관하거나 전송하기 전에 저장하는 곳으로 사용된다.

더블 버퍼링에서는 실제로 화면에 표시되는 데이터가 저장되는 프론트 버퍼(Front Buffer)과 그려질 데이터가 저장되는 백 버퍼(Back Buffer)이 있다.

 

더블 버퍼링 동장 방식

먼저 게임이나 앱에서 화면에 그릴 데이터를 백 버퍼(Back Buffer)에 먼저 그린다. 예를 들어서 테트리스 게임 판, 블럭 등을 백 버퍼에 그린다. 백 버퍼에 그릴 데이터들이 모두 준비되면, 그 내용을 프론트 버퍼(Front Buffer)로 빠르게 교체한다. 이 과정은 매우 빠르게 일어나기 때문에 깜빡임 없이 새로운 화면을 바로 보여줄 수 있다. 원래는 화면을 업데이트 할 때마다 새로 그렸지만, 더블 버퍼링을 사용함으로써 그 다음 화면이 미리 준비되어 있기 때문에 새로 그려짐으로써 발생하는 깜빡임이 사라지는 것이다.

 

더블 버퍼링 예시

#include <iostream>
#include <windows.h>

const int WIDTH = 10;
const int HEIGHT = 5;

CHAR_INFO buffer[WIDTH * HEIGHT];
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
COORD bufferSize = { WIDTH, HEIGHT };
COORD bufferCoord = { 0, 0 };
SMALL_RECT writeRegion = { 0, 0, WIDTH - 1, HEIGHT - 1 };

void printMaze() {
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            int index = y * WIDTH + x;
            buffer[index].Char.AsciiChar = (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1) ? '#' : ' ';
            buffer[index].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
        }
    }
    WriteConsoleOutput(hConsole, buffer, bufferSize, bufferCoord, &writeRegion);
}

int main() {
    printMaze();  // 미로 출력
    system("pause");
    return 0;
}

 

위 코드는 미로를 출력하는 간단한 코드입니다. 여기서 사용자가 움직이는 것까지 재현하면 더블 버퍼링의 효과를 잘 볼 수 있습니다.

 

CHAR_INFO buffer[WIDTH * HEIGHT];

 

CHAR_INFO: 각 콘솔 셀에 대한 정보를 저장하는 구조체이다. 각 셀은 문자와 해당 문자의 속성을 가질 수 있다.

buffer[WIDTH * HEIGHT] : WIDTH와 HEIGHT를 곱한 크기만큼의 CHAR_INFO 배열을 만든다.

 

HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

 

GetStdHandle(STD_OUTPUT_HANDLE): 콘솔 출력 핸들을 얻는 함수이다. 이 핸들을 통해 콘솔 출력 작업을 할 수 있다.

HANDLE은 Windows 운영체제에서 파일, 콘솔, 창 등의 자원에 접근하거나 조작할 수 있는 식별자이다. 핸들을 통해 시스템에서 자원을 다룰 수 있다.

 

COORD bufferSize = { WIDTH, HEIGHT };

 

COORD: x, y 좌표를 나타내는 구조체이다. 여기서는 버퍼의 크기를 정의하는 데 사용된다. 좌표 지정에도 사용된다.

 

COORD bufferCoord = { 0, 0 };

 

bufferCoord: 콘솔에서 출력할 버퍼의 시작 좌표이다. (0, 0)은 왼쪽 상단이다.

 

SMALL_RECT writeRegion = { 0, 0, WIDTH - 1, HEIGHT - 1 };

 

SMALL_RECT: 사각형 범위를 정의하는 구조체이다. WriteConsoleOutput이 출력할 화면의 영역을 지정한다. (0, 0)은 시작 좌표이고, (WIDTH-1, HEIGHT-1)은 끝 좌표로 미로의 경계이다.

 

void printMaze() {
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            int index = y * WIDTH + x;

 

for 루프는 미로를 구성하는 각 셀을 순차적으로 출려갛기 위한 루프이다.

index = y * WIDHT + x: 2D 좌표를 1D 배열 인덱스로 변환하는 식이다. 콘솔 출력은 1D 배열이므로 좌표를 하나의 인덱스로 변환하여 배열에 접근할 수 있게 한다.

 

buffer[index].Char.AsciiChar = (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1) ? '#' : ' ';

 

CHAR_INFO 구조체의 Char 필드는 출력할 문자를 저장합니다. 이 코드에서는 x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1 조건을 통해 벽은 "#"을 출력하고, 나머지 부분은 공백으로 채워집니다.

Char.AsciiChar: 문자를 나타내는 부분으로 현재 인덱스에 해당하는 버퍼 위치에 출력할 문자를 지정한다.

조건식을 풀어보자.

x == 0 : x가 0이면 왼쪽 경계이다.

x == WIDHT- 1: x가 WIDTH - 1이면 오른쪽 경계이다.

y == 0: y가 0이면 상단 경계이다.

y == HEIGHT -1 : y가 HEIGHT - 1 이면 하단 경계이다.

 

? '#' : ' ' : 조건이 거짓이면 공백이 출력되고, 참이면 '#'이 출력된다.

#####
#   #
#   #
#   #
#####

 

buffer[index].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;

Attributes 필드는 문자의 속성을 설정한다. 여기서는 흰색을 의미한다.

 

WriteConsoleOutput(hConsole, buffer, bufferSize, bufferCoord, &writeRegion);

 

WriteConsoleOutput은 콘솔에 실제로 출력하는 함수이다. 이 함수는 화면에 출력할 CHAR_INFO 배열(buffer), 출력할 크기(bufferSize), 출력할 시작 좌표(bufferCoord), 출력할 영영(writeRegion)으 받아서 콘솔에 내용을 표시한다. hConsole은 콘솔에 출력할 수 있도록 하는 핸들이다.

반응형

'C' 카테고리의 다른 글

C 강좌 2강 - 변수와 상수  (2) 2025.06.13
C 강좌 1강 - Hello World 출력해보기  (0) 2025.06.13
C 강좌 0강 - 개발 환경 준비하기  (0) 2024.11.24