327 lines
9.7 KiB
C++
327 lines
9.7 KiB
C++
/******************************************************************
|
||
* !注意! *
|
||
* 本头文件中为你封装了WinAPI中有关Console绘制的底层函数,可以帮助你快 *
|
||
* 速绘制你想要的输出,效率比printf+cls高出很多。 *
|
||
* 函数使用详见demo.cpp中的几个示例。 *
|
||
******************************************************************/
|
||
#ifndef FAST_PRINTER_H
|
||
#define FAST_PRINTER_H
|
||
#include <windows.h>
|
||
|
||
/******************************************************************
|
||
* TO-DO: *
|
||
* *
|
||
* 本文件你可以自由进行修改,如将其中的一些接收参数设置为你实现的Array *
|
||
* 或为了配合你的实现进行一些便携化成员函数的编写等,甚至自己重新实现 *
|
||
* 一个更高效的。 *
|
||
* *
|
||
******************************************************************/
|
||
|
||
namespace fp_color {
|
||
// f is the foreground color b is the background color
|
||
// console color format: (f | b)
|
||
const SHORT f_black = 0;
|
||
const SHORT f_blue = 0x0001;
|
||
const SHORT f_green = 0x0002;
|
||
const SHORT f_aqua = 0x0003;
|
||
const SHORT f_red = 0x0004;
|
||
const SHORT f_purple = 0x0005;
|
||
const SHORT f_yellow = 0x0006;
|
||
const SHORT f_white = 0x0007;
|
||
const SHORT f_gray = 0x0008;
|
||
const SHORT f_l_blue = 0x0009;
|
||
const SHORT f_l_green = 0x000A;
|
||
const SHORT f_l_aqua = 0x000B;
|
||
const SHORT f_l_red = 0x000C;
|
||
const SHORT f_l_purple = 0x000D;
|
||
const SHORT f_l_yellow = 0x000E;
|
||
const SHORT f_l_white = 0x000F;
|
||
|
||
const SHORT b_black = 0;
|
||
const SHORT b_blue = 0x0010;
|
||
const SHORT b_green = 0x0020;
|
||
const SHORT b_aqua = 0x0030;
|
||
const SHORT b_red = 0x0040;
|
||
const SHORT b_purple = 0x0050;
|
||
const SHORT b_yellow = 0x0060;
|
||
const SHORT b_white = 0x0070;
|
||
const SHORT b_gray = 0x0080;
|
||
const SHORT b_l_blue = 0x0090;
|
||
const SHORT b_l_green = 0x00A0;
|
||
const SHORT b_l_aqua = 0x00B0;
|
||
const SHORT b_l_red = 0x00C0;
|
||
const SHORT b_l_purple = 0x00D0;
|
||
const SHORT b_l_yellow = 0x00E0;
|
||
const SHORT b_l_white = 0x00F0;
|
||
}
|
||
|
||
class FastPrinter {
|
||
public:
|
||
FastPrinter(DWORD, DWORD);
|
||
FastPrinter(DWORD, DWORD, WORD);
|
||
~FastPrinter();
|
||
|
||
void setData(const char*, const WORD*);
|
||
void setData(const char*, const WORD*, SMALL_RECT);
|
||
void setRect(SMALL_RECT, const char, const WORD);
|
||
void fillRect(SMALL_RECT, const char, const WORD);
|
||
void setText(COORD, const char*, const WORD, const WORD);
|
||
void setText(COORD, const char*, const WORD);
|
||
void setText(COORD, const char*);
|
||
|
||
void cleanSrceen();
|
||
void draw(bool);
|
||
private:
|
||
HANDLE hOutput, hOutBuf, hTmpBuf;
|
||
COORD coordBufSize;
|
||
COORD coordBufCoord;
|
||
DWORD bytes = 0;
|
||
DWORD sizeX, sizeY;
|
||
|
||
char* dataGrid;
|
||
WORD* colorGrid;
|
||
CHAR_INFO* outputGrid;
|
||
SMALL_RECT srctWriteRect;
|
||
|
||
void initDrawer();
|
||
void _setFontSize(const WORD);
|
||
void _destroy();
|
||
|
||
void _swapBuf();
|
||
void _draw();
|
||
void _drawC();
|
||
};
|
||
|
||
FastPrinter::FastPrinter(DWORD x, DWORD y) :sizeX(x), sizeY(y) {
|
||
initDrawer();
|
||
}
|
||
|
||
FastPrinter::FastPrinter(DWORD x, DWORD y, WORD fontSize) : sizeX(x), sizeY(y) {
|
||
// init with font size
|
||
_setFontSize(fontSize);
|
||
initDrawer();
|
||
}
|
||
|
||
FastPrinter::~FastPrinter() {
|
||
_destroy();
|
||
}
|
||
|
||
void FastPrinter::setData(const char* _in_data, const WORD* _in_color) {
|
||
// copy the data to inner buffer
|
||
memcpy(dataGrid, _in_data, sizeX * sizeY);
|
||
memcpy(colorGrid, _in_color, sizeX * sizeY * sizeof(WORD));
|
||
}
|
||
|
||
void FastPrinter::setData(const char* _in_data, const WORD* _in_color, SMALL_RECT _area) {
|
||
// copy the data to the specified area
|
||
SHORT row = (_area.Right - _area.Left);
|
||
for (WORD _i = _area.Top, i = 0; _i < _area.Bottom; _i++, i++) {
|
||
memcpy(dataGrid + (_i * sizeX + _area.Left), _in_data + (i * row), row);
|
||
memcpy(colorGrid + (_i * sizeX + _area.Left), _in_color + (i * row), row * sizeof(WORD));
|
||
}
|
||
}
|
||
|
||
void FastPrinter::setRect(SMALL_RECT _area, const char _val, const WORD _color) {
|
||
// draw a hollow rectangle
|
||
for (WORD i = _area.Left; i < _area.Right; i++) {
|
||
dataGrid[_area.Top * sizeX + i] = _val;
|
||
dataGrid[(_area.Bottom - 1) * sizeX + i] = _val;
|
||
|
||
colorGrid[_area.Top * sizeX + i] = _color;
|
||
colorGrid[(_area.Bottom - 1) * sizeX + i] = _color;
|
||
}
|
||
|
||
for (WORD i = _area.Top; i < _area.Bottom; i++) {
|
||
dataGrid[i * sizeX + _area.Left] = _val;
|
||
dataGrid[i * sizeX + _area.Right - 1] = _val;
|
||
|
||
colorGrid[i * sizeX + _area.Left] = _color;
|
||
colorGrid[i * sizeX + _area.Right - 1] = _color;
|
||
}
|
||
}
|
||
|
||
void FastPrinter::fillRect(SMALL_RECT _area, const char _val, const WORD _color) {
|
||
// draw a solid rectangle
|
||
SHORT row = (_area.Right - _area.Left);
|
||
for (WORD _i = _area.Top, i = 0; _i < _area.Bottom; _i++, i++) {
|
||
memset(dataGrid + (_i * sizeX + _area.Left), _val, row);
|
||
for (WORD _j = _area.Left; _j < _area.Right; _j++) {
|
||
colorGrid[_i * sizeX + _j] = _color;
|
||
}
|
||
}
|
||
}
|
||
|
||
void FastPrinter::setText(COORD _pos, const char* _val, const WORD _color, const WORD len) {
|
||
// print text with position and color
|
||
// Note: try not to set text with '\n'
|
||
memcpy(dataGrid + (_pos.Y * sizeX + _pos.X), _val, len);
|
||
for (WORD i = _pos.X; i < _pos.X + len; i++) {
|
||
colorGrid[_pos.Y * sizeX + i] = _color;
|
||
}
|
||
}
|
||
|
||
void FastPrinter::setText(COORD _pos, const char* _val, const WORD _color) {
|
||
// print text with position and color but no len
|
||
WORD len = (WORD)strlen(_val);
|
||
memcpy(dataGrid + (_pos.Y * sizeX + _pos.X), _val, len);
|
||
for (WORD i = _pos.X; i < _pos.X + len; i++) {
|
||
colorGrid[_pos.Y * sizeX + i] = _color;
|
||
}
|
||
}
|
||
|
||
void FastPrinter::setText(COORD _pos, const char* _val) {
|
||
// print text with position but no len
|
||
WORD len = (WORD)strlen(_val);
|
||
memcpy(dataGrid + (_pos.Y * sizeX + _pos.X), _val, len);
|
||
for (WORD i = _pos.X; i < _pos.X + len; i++) {
|
||
colorGrid[_pos.Y * sizeX + i] = fp_color::f_l_white;
|
||
}
|
||
}
|
||
|
||
void FastPrinter::_setFontSize(const WORD x) {
|
||
CONSOLE_FONT_INFOEX cfi;
|
||
cfi.cbSize = sizeof(cfi);
|
||
GetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
|
||
cfi.dwFontSize.X = 0;
|
||
cfi.dwFontSize.Y = x;
|
||
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
|
||
}
|
||
|
||
|
||
void FastPrinter::cleanSrceen() {
|
||
memset(dataGrid, 0, sizeX * sizeY);
|
||
memset(colorGrid, 0, sizeX * sizeY * sizeof(WORD));
|
||
memset(outputGrid, 0, sizeX * sizeY * sizeof(CHAR_INFO));
|
||
}
|
||
|
||
void FastPrinter::draw(bool withColor) {
|
||
// flush the whole screen
|
||
if (withColor)_drawC();
|
||
else _draw();
|
||
_swapBuf();
|
||
}
|
||
|
||
void FastPrinter::initDrawer() {
|
||
// init the data buffer
|
||
dataGrid = new char[sizeX * sizeY];
|
||
memset(dataGrid, 0, sizeX * sizeY);
|
||
|
||
colorGrid = new WORD[sizeX * sizeY];
|
||
memset(colorGrid, 0, sizeX * sizeY * sizeof(WORD));
|
||
|
||
outputGrid = new CHAR_INFO[sizeX * sizeY];
|
||
memset(outputGrid, 0, sizeX * sizeY * sizeof(CHAR_INFO));
|
||
|
||
// set the draw area
|
||
srctWriteRect.Top = 0;
|
||
srctWriteRect.Left = 0;
|
||
srctWriteRect.Bottom = (SHORT)(sizeY - 1);
|
||
srctWriteRect.Right = (SHORT)(sizeX - 1);
|
||
|
||
// get font size
|
||
CONSOLE_FONT_INFOEX cfi;
|
||
cfi.cbSize = sizeof(cfi);
|
||
GetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
|
||
|
||
// load the external WinAPI Module
|
||
typedef HWND(WINAPI *PROCGETCONSOLEWINDOW)();
|
||
PROCGETCONSOLEWINDOW GetConsoleWindow;
|
||
HMODULE hKernel32 = GetModuleHandleA("kernel32");
|
||
GetConsoleWindow = (PROCGETCONSOLEWINDOW)GetProcAddress(hKernel32, "GetConsoleWindow");
|
||
|
||
// get console window handle and move the window to the upper left
|
||
HWND hwnd = GetConsoleWindow();
|
||
SetWindowPos(hwnd, HWND_TOP, 0, 0, cfi.dwFontSize.X * sizeX, cfi.dwFontSize.Y * sizeY, 0);
|
||
|
||
// resize the window
|
||
char cmd_buffer[32] = "mode con: cols=0000 lines=0000";
|
||
cmd_buffer[15] = '0' + (sizeX / 1000 % 10);
|
||
cmd_buffer[16] = '0' + (sizeX / 100 % 10);
|
||
cmd_buffer[17] = '0' + (sizeX / 10 % 10);
|
||
cmd_buffer[18] = '0' + sizeX % 10;
|
||
|
||
cmd_buffer[26] = '0' + (sizeY / 1000 % 10);
|
||
cmd_buffer[27] = '0' + (sizeY / 100 % 10);
|
||
cmd_buffer[28] = '0' + (sizeY / 10 % 10);
|
||
cmd_buffer[29] = '0' + sizeY % 10;
|
||
|
||
system(cmd_buffer);
|
||
|
||
// create output buffer
|
||
hOutBuf = CreateConsoleScreenBuffer(
|
||
GENERIC_WRITE | GENERIC_READ,
|
||
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||
NULL,
|
||
CONSOLE_TEXTMODE_BUFFER,
|
||
NULL
|
||
);
|
||
|
||
hOutput = CreateConsoleScreenBuffer(
|
||
GENERIC_WRITE | GENERIC_READ,
|
||
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||
NULL,
|
||
CONSOLE_TEXTMODE_BUFFER,
|
||
NULL
|
||
);
|
||
|
||
// invisible the cursor
|
||
CONSOLE_CURSOR_INFO cci;
|
||
cci.bVisible = 0;
|
||
cci.dwSize = 1;
|
||
SetConsoleCursorInfo(hOutput, &cci);
|
||
SetConsoleCursorInfo(hOutBuf, &cci);
|
||
}
|
||
|
||
void FastPrinter::_destroy() {
|
||
// clean up memory
|
||
delete[] dataGrid;
|
||
delete[] colorGrid;
|
||
delete[] outputGrid;
|
||
|
||
CloseHandle(hOutBuf);
|
||
CloseHandle(hOutput);
|
||
}
|
||
|
||
void FastPrinter::_swapBuf() {
|
||
// core function: display after the data has been set
|
||
hTmpBuf = hOutBuf;
|
||
hOutBuf = hOutput;
|
||
hOutput = hTmpBuf;
|
||
}
|
||
|
||
void FastPrinter::_draw() {
|
||
for (DWORD i = 0; i < sizeY; i++) {
|
||
// draw every line
|
||
coordBufCoord.Y = (SHORT)i;
|
||
WriteConsoleOutputCharacterA(hOutput, dataGrid + (i * sizeX), sizeX, coordBufCoord, &bytes);
|
||
}
|
||
SetConsoleActiveScreenBuffer(hOutput);
|
||
}
|
||
|
||
void FastPrinter::_drawC() {
|
||
for (DWORD i = 0; i < sizeY; i++) {
|
||
for (DWORD j = 0; j < sizeX; j++) {
|
||
// copy info to CHAR_INFO struct
|
||
// this will draw with color
|
||
outputGrid[i * sizeX + j].Attributes = colorGrid[i * sizeX + j];
|
||
outputGrid[i * sizeX + j].Char.AsciiChar = dataGrid[i * sizeX + j];
|
||
}
|
||
}
|
||
|
||
coordBufCoord.X = 0;
|
||
coordBufCoord.Y = 0;
|
||
coordBufSize.X = (SHORT)(sizeX);
|
||
coordBufSize.Y = (SHORT)(sizeY);
|
||
|
||
WriteConsoleOutputA(
|
||
hOutput, // screen buffer to write to
|
||
outputGrid, // buffer to copy from
|
||
coordBufSize, // col-row size of chiBuffer
|
||
coordBufCoord, // top left src cell in chiBuffer
|
||
&srctWriteRect); // dest. screen buffer rectangle
|
||
SetConsoleActiveScreenBuffer(hOutput);
|
||
}
|
||
/******************************************************************
|
||
* TO-DO END *
|
||
******************************************************************/
|
||
#endif |