Frame Back Buffer

So, I've read about the Frame Back Buffer and I'd like to know how it works.
From what I found out is that you have 2 images, the front one (physical map on display) and the back one (logical map). Whenever something happens you alter the logical map and then switch the two.
The aim of this is to prevent flickering.

1) How does it work?
2) But doesn't the screen flicker once when you switch the two maps?

3) Here's some code that displays a physical (there's only 1 map currently) map and randomly moves all of the S around the map. How can I change that so it doesn't flicker?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <ctime>

void ClearScreen();

int main()
{
    srand(time(0));

    struct position
    {
        int CurrentX, CurrentY;
        int NewX, NewY;
    } Enemy;

char (* Map)[20][40];
char map1[20][40] =
{"#######################################",
 "#                                     #",
 "#                                     #",
 "#                  S                  #",
 "#     S                               #",
 "#                                     #",
 "#                                     #",
 "#                                     #",
 "#            S             S          #",
 "#                                     #",
 "#                                     #",
 "#                        S            #",
 "#     S                               #",
 "#                                     #",
 "#######################################"};

short random = 0;
Map = &map1;

 while(true)
 {
    ClearScreen();
    for (int i = 0; i < 20; i++)
    {
    std::cout << (* Map)[i] << "\n";
    }

    for (Enemy.CurrentY = 0; Enemy.CurrentY < 20; Enemy.CurrentY++)
    {
    for (Enemy.CurrentX = 0; Enemy.CurrentX < 40; Enemy.CurrentX++)
    {
        switch ((* Map)[Enemy.CurrentY][Enemy.CurrentX])
        {
            case 'S':
            Enemy.NewX = Enemy.CurrentX, Enemy.NewY = Enemy.CurrentY;
            random = rand() % 4 + 1;
            if (random == 1) {Enemy.NewY -= 1;}
            if (random == 2) {Enemy.NewY += 1;}
            if (random == 3) {Enemy.NewX -= 1;}
            if (random == 4) {Enemy.NewX += 1;}

                switch((*Map)[Enemy.NewY][Enemy.NewX])
                {
                    case ' ':
                    (*Map)[Enemy.CurrentY][Enemy.CurrentX] = ' ';
                    Enemy.CurrentX = Enemy.NewX; Enemy.CurrentY = Enemy.NewY;
                    (*Map)[Enemy.NewY][Enemy.NewX] = 'S';
                    break;

                    default:
                    random = 0;
                    break;
                }
            break;
        }
    }
    }

    Sleep(200);
 }

return 0;
}

void ClearScreen()
{
  HANDLE                     hStdOut;
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  DWORD                      count;
  DWORD                      cellCount;
  COORD                      homeCoords = { 0, 0 };

  hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
  if (hStdOut == INVALID_HANDLE_VALUE) return;

  /* Get the number of cells in the current buffer */
  if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
  cellCount = csbi.dwSize.X *csbi.dwSize.Y;

  /* Fill the entire buffer with spaces */
  if (!FillConsoleOutputCharacter(
    hStdOut,
    (TCHAR) ' ',
    cellCount,
    homeCoords,
    &count
    )) return;

  /* Fill the entire buffer with the current colors and attributes */
  if (!FillConsoleOutputAttribute(
    hStdOut,
    csbi.wAttributes,
    cellCount,
    homeCoords,
    &count
    )) return;

  /* Move the cursor home */
  SetConsoleCursorPosition( hStdOut, homeCoords );
}
closed account (zb0S216C)
Vidminas wrote:
"1) How does it work?"

You've already answered your question. But, just to clarify: double-buffering is where you have two surfaces [the front- and back-buffer] in memory. One of surfaces is the front-buffer which is what is the user is seeing on the screen. The back-buffer is what the program renders the screen output to. Once rendering to the back-buffer has finished, the entire surface is then rasterised which converts the entire back-buffer into an array of pixels. After the rasterisation of the back-buffer, the front-buffer is exchanged with the back-buffer, which updates the screen to the next frame.

Vidminas wrote:
"2) But doesn't the screen flicker once when you switch the two maps?"

Yes. Irrespective of how fast the two buffers are switched, a flicker will occur. However, the human eye blends the transition between the two surfaces as if the switch as seamless. Though, sometimes, the time taken to switch between buffers takes so long that the human eye can spot to transition between the two buffers which spoils the seamless transition illusion.

In addition, double-buffering consumes 2x more memory than using a single buffer, but reaps more benefits such as smoother rendering. Sometimes, developers go one step further and use triple- or quad-buffering.

Wazzak
Last edited on
The simplest way in this case to avoid the flicker is to not call the ClearScreen() function.

Instead, just move the cursor position back to the start, maybe like this:

1
2
3
4
5
6
7
8
9
10
11
12
void home()
{
    HANDLE  hStdOut;
    COORD   homeCoords = { 0, 0 };
    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

    if (hStdOut == INVALID_HANDLE_VALUE)
        return;

    /* Move the cursor home */
    SetConsoleCursorPosition( hStdOut, homeCoords );
}


or use gotoxy() if it is available in <conio.h>.
It worked! Thank you, I was using the function to move the cursor home before, but I never realised that I could use it in this code ;)
Topic archived. No new replies allowed.