In the C language to write the game of the small partners must initially encounter such a problem, in the process of continuously clear the output data, the console output will be constantly flashing screen. This problem occurs because the time the program spends on data processing affects the display, and perhaps you can use the local overlay Update method (which reduces the amount of updated data) to mitigate the splash screen, but this approach does not apply to all occasions, especially if the update data itself is very large.
This article will address the end-level resolution of the console application output splash screen-double buffering.
Problem Presentation
The following code demonstrates the splash screen problem in the process of continuously clearing the screen output data at high speed, and invited you to try:
12345678910111213141516 |
#include <stdio.h>
int main()
{
while (1)
{
for (
char c=
‘a‘
; c<
‘z‘
; c++)
{
system
(
"cls"
);
for (
int i=0; i<800; i++)
{
printf
(
"%c"
,c);
}
}
}
}
|
Incomplete Solution: Partial overwrite update
This example code will use two Win32 API functions, GetStdHandle, SetConsoleCursorPosition,
Legend |
Name |
Description |
|
HANDLE GetStdHandle ( _in_ DWORD Nstdhandle ); |
Get Standard device handle Nstdhandle standard equipment, desirable values: Std_input_handle (DWORD)-10, input device Std_output_handle (DWORD)-11, output device Std_error_handle (DWORD)-12, error device Call Back: Successful, returns the device handle (HANDLE); Failure, return invalid_handle_value; If there is no standard device, returns NULL. |
|
BOOL SetConsoleCursorPosition ( _in_ HANDLE Hconsoleoutput, _in_ COORD dwcursorposition ); |
Setting the console cursor position Hconsoleoutput Console output device handle dwcursorposition cursor Position |
The COORD structure is used in the function arguments:
Legend |
Name |
Description |
|
X Short X; |
Horizontal coordinate or column value, starting with 0 |
|
Y Short X; |
Vertical coordinate or row value, starting with 0 |
Example code:
123456789101112131415161718192021 |
#include <stdio.h>
#include <Windows.h> int main()
{
HANDLE hOutput;
COORD coord={0,0};
hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
while (1)
{
for (
char c=
‘a‘
; c<
‘z‘
; c++)
{
SetConsoleCursorPosition(hOutput, coord);
for (
int i=0; i<800; i++)
{
printf
(
"%c"
,c);
}
}
}
}
|
Flash screen causes and solutions
First of all, it is stated that only the data in the "Display buffer" will be displayed. The display structure of the default console application is this:
When the output of a large amount of data, because the data processing takes time, resulting in data arrival in the display buffer sequence. That is, when the monitor displays data, it is possible that only some of the displayed data has reached the display buffer, and the other data has not arrived, so that the image is displayed as a partial rendering complete. This is the root cause of the splash screen that updates a large number of display data.
Complete Solution: Using dual buffering technology
In the process of graphics processing, double buffering is one of the basic techniques, it is an effective solution to solve the flash screen. Especially in the field of game programming, double buffering technology has been widely used.
So it seems that the problem of seeming to be worried, in fact, we only need one more buffer to completely solve this problem. If you apply a dual-buffering technique, the structure of the console program will change slightly:
Because the default buffer has support for standard input and output streams, for ease of input and output, we use the default display buffer as the back buffer and the newly created display buffer as the active screen. The basic procedure is to first display the data to the default buffer, and then fill in the newly created display buffer once it is all written.
To implement this process, we also need to invoke several Win32 APIs (Createconsolescreenbuffer, Setconsoleactivescreenbuffer, Setconsolecursorinfo, Readconsoleoutputcharactera, Writeconsoleoutputcharactera),
Legend |
Name |
Description |
|
HANDLE winapicreateconsolescreenbuffer ( _In_ dword dwdesiredaccess, _In_ DWORD dwShareMode, _In_opt_ const security_attributes *lpsecurityattributes, _in_ dword dwflags, _Reserved_ Lpvoidlpscreenbufferdata ); |
Create console display buffer dwdesiredaccess, console buffering security and access, desirable value: generic _read (0x80000000l), Read permissions Generic_write (0x40000000l), write permissions dwsharemode, shared mode, desirable value: Span style= "Font-size:xx-small;" >file_share_read, read share File_share_write, write share lpsecurityattributes, security properties, NULL dwflags, buffer type, Optional: console_textmode_buffer, console text-mode buffering lpscreenbufferdata, reserved, NULL |
|
BOOL Winapisetconsoleactivescreenbuffer ( _in_ HANDLE Hconsoleoutput ); |
Setting Console activity display buffering Hconsoleoutput, console output device handle |
|
BOOL Winapisetconsolecursorinfo ( _in_ HANDLE Hconsoleoutput, _in_ Const Console_cursor_info *lpconsolecursorinfo ); |
Setting Console cursor Information Hconsoleoutput, console output device handle Lpconsolecursorinfo, cursor information (size, visibility) |
|
BOOL winapireadconsoleoutputcharactera ( _In_ HANDLE Hconsoleoutput, _out_ lptstr lpcharacter, _in_ dword nlength , _in_ coord dwreadcoord, _out_ lpdwordlpnumbersofcharsread ); |
read console output to character array hconsoleoutput, console output device handle Lpcharacter, saved character array pointer Nlength, read length Dwreadcoord , read start coordinate lpnumbersofcharsread, actual read length |
|
BOOL Winapiwriteconsoleoutputcharactera ( _in_ HANDLE Hconsoleoutput, _in_ LPTSTR Lpcharacter, _in_ DWORD Nlength, _in_ COORD Dwwritecoord, _out_ Lpdwordlpnumberofcharswritten ); |
Writes a character array to the console output Hconsoleoutput, console output device handle Lpcharacter, writing a character array pointer Nlength, write length Dwwritecoord, write start coordinate lpnumberofcharswritten, actual write length |
The CONSOLE_CURSOR_INFO structure is used in the function arguments:
Legend |
Name |
Description |
|
dwsize DWORD dwsize; |
The cursor size, in the range 1 to 100 to take the value. |
|
Bvisible BOOL bvisible; |
Visibility, desirable value: false,0, not visible; true,1, visible. |
Example code:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546 |
#include <stdio.h>
#include <Windows.h>
int main(){
//获取默认标准显示缓冲区句柄
HANDLE hOutput;
COORD coord={0,0};
hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
//创建新的缓冲区
HANDLE hOutBuf = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
//设置新的缓冲区为活动显示缓冲
SetConsoleActiveScreenBuffer(hOutBuf);
//隐藏两个缓冲区的光标
CONSOLE_CURSOR_INFO cci;
cci.bVisible=0;
cci.dwSize=1;
SetConsoleCursorInfo(hOutput, &cci);
SetConsoleCursorInfo(hOutBuf, &cci);
//双缓冲处理显示
DWORD bytes=0;
char data[800];
while (1)
{
for (
char c=
‘a‘
; c<
‘z‘
; c++)
{
system
(
"cls"
);
for (
int i=0; i<800; i++)
{
printf
(
"%c"
,c);
}
ReadConsoleOutputCharacterA(hOutput, data, 800, coord, &bytes);
WriteConsoleOutputCharacterA(hOutBuf, data, 800, coord, &bytes);
}
}
return 0;
}
|
Dual Buffer Solution Console Application Output "splash screen" (c/c++,windows)