我有兩個緩沖區,大小和型別都相同(uint32_t*)。這些緩沖區應該代表渲染/繪圖系統的前緩沖區和后緩沖區。它們存盤 32 位像素資料。
我使用以下方法宣告和初始化這些緩沖區;
private:
...
uint32_t* frontBuf;
uint32_t* backBuf;
size_t gbufSize;
...
public:
void Initialize() {
...
// prepare for rendering
gbufSize = sizeof(uint32_t) * w * h;
backBuf = (uint32_t*)malloc(gbufSize);
frontBuf = (uint32_t*)malloc(gbufSize);
...
}
我還使用以下方法獲取控制臺的輸出、視窗和設備句柄Initialize():
// get handles
cwd = GetDC(GetConsoleWindow());
chd = GetStdHandle(STD_OUTPUT_HANDLE);
cwn = GetConsoleWindow();
然后我有一些繪圖方法,比如一個SetPixel方法:
size_t GFlatten(int x, int y) {
return y * h x;
}
void GSetPixel(int x, int y, uint32_t color) {
backBuf[GFlatten(x, y)] = color;
}
最后,我有一個GSwap方法。這個方法應該交換緩沖區的指標,清除新的后臺緩沖區并將前臺緩沖區復制到螢屏上。
前兩個作業(我認為),但我不知道如何實作第三個(復制到螢屏)。我寧愿不使用任何外部庫。
方法代碼GSwap:
void GSwap() {
// swap pointers
uint32_t* frontTmp = frontBuf;
frontBuf = backBuf;
backBuf = frontTmp;
// clear new back buffer
memset(backBuf, 0, gbufSize);
// draw on screen
/* ??? */
}
完整代碼:Pastebin
uj5u.com熱心網友回復:
您不能通過將位元組插入某個緩沖區來繪制到任意視窗。Win32 是比它更高級別的 API。
但是,可以通過寫入緩沖區來繪制位圖。您創建一個位圖,這樣當您使用CreateDIBSection(...). BitBlt然后,您可以通過適當的設備背景關系等將該位圖繪制到視窗。
下面是一個最小的例子。(我保留了您對后緩沖區和前緩沖區的使用,即使在這里實際上并不需要。視窗本身本質上是一個前緩沖區,因此您只需要一個后緩沖區的“交換鏈”就不會出現閃爍。 )
#include <windows.h>
#include <stdint.h>
#include <utility>
#include <algorithm>
constexpr int kTimerID = 101;
LRESULT CALLBACK wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
struct graphics_buffer {
HBITMAP hbm;
uint32_t* data;
};
graphics_buffer create_graphics_buffer(int wd, int hgt)
{
HDC hdcScreen = GetDC(NULL);
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = wd;
bmi.bmiHeader.biHeight = -hgt; // top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
graphics_buffer gb;
gb.hbm = CreateDIBSection(hdcScreen, &bmi, DIB_RGB_COLORS, reinterpret_cast<void**>(&gb.data), NULL, NULL);
ReleaseDC(NULL, hdcScreen);
return gb;
}
class graphic_buffers {
graphics_buffer front_;
graphics_buffer back_;
int wd_;
int hgt_;
public:
graphic_buffers(int wd, int hgt) :
wd_(wd),
hgt_(hgt),
front_(create_graphics_buffer(wd, hgt)),
back_(create_graphics_buffer(wd, hgt))
{
clear();
}
HBITMAP front_bmp() {
return front_.hbm;
}
void swap() {
std::swap(front_, back_);
}
size_t size() const {
return static_cast<size_t>(wd_ * hgt_);
}
int width() const {
return wd_;
}
int height() const {
return hgt_;
}
void clear() {
std::fill(back_.data, back_.data size(), 0);
}
void set_pixel(int x, int y, uint32_t pix) {
back_.data[y * wd_ x] = pix;
}
~graphic_buffers() {
DeleteObject(front_.hbm);
DeleteObject(back_.hbm);
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = wndproc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"swap_buffers_window";
if (!RegisterClass(&wc))
return 1;
if (!CreateWindow(wc.lpszClassName,
L"buffered window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, 0, 0, hInstance, NULL))
return 2;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
void draw_something(graphic_buffers& buffs) {
int wd = buffs.width();
int hgt = buffs.height();
static int x = 0;
static int y = 0;
static int x_vel = 4;
static int y_vel = 7;
if (x >= 0 && x < wd && y >= 0 && y < hgt) {
buffs.set_pixel(x, y, 0xffffffff);
}
x = x_vel;
y = y_vel;
if (x < 0 || x > wd) {
x_vel *= -1;
}
if (y < 0 || y > hgt) {
y_vel *= -1;
}
}
LRESULT CALLBACK wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE: {
RECT r;
GetClientRect(hWnd, &r);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(new graphic_buffers(r.right - r.left, r.bottom - r.top)));
SetTimer(hWnd, kTimerID, 1, NULL);
}
break;
case WM_TIMER: {
auto buffs = reinterpret_cast<graphic_buffers*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
draw_something(*buffs);
buffs->swap();
buffs->clear();
InvalidateRect(hWnd, NULL, FALSE);
}
break;
case WM_PAINT: {
auto buffs = reinterpret_cast<graphic_buffers*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HDC hdc_bmp = CreateCompatibleDC(hdc);
auto old_bmp = SelectObject(hdc_bmp, buffs->front_bmp());
BitBlt(hdc, 0, 0, buffs->width(), buffs->height(), hdc_bmp, 0, 0, SRCCOPY);
SelectObject(hdc, old_bmp);
DeleteDC(hdc_bmp);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY: {
auto buffs = reinterpret_cast<graphic_buffers*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
delete buffs;
}
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/415713.html
標籤:
上一篇:使用C 捕獲特定視窗會回傳舊資料
