调整 window 的大小会导致位图被覆盖
Resizing the window results in bitmaps being overwritten
我一直在 Visual C++ 中处理位图和渲染,遇到了一个奇怪的问题。
我正在尝试让绘图区域在用户调整 window 大小时调整大小。现在,不仅扩大 window 不会扩大可见绘图区域(白色边框出现在原始 window 边界之外),而且更改 window 大小似乎很麻烦用我的位图。
这是游戏启动时的样子:
更改 window 的宽度或高度后,紫色字符现在已被橙色字符替换。
最后,三个都变成了蓝色。
如果我继续下去,所有字符都会被绿草背景位图覆盖。
它似乎以位图呈现的相反顺序发生。添加第二行字符确认它在呈现代码中不是问题 - 内存中的实际位图正在以某种方式改变。删除调整大小代码会导致位图错误停止重现。
当我尝试重新初始化设备上下文时,几乎可以肯定这是我的调整大小代码中的一个错误,但我不确定它是什么。
这里是相关的设置代码:
HBITMAP player_blue = (HBITMAP) LoadImage (NULL, L"Images/test_player_blue.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP player_orange = (HBITMAP) LoadImage (NULL, L"Images/test_player_orange.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP player_purple = (HBITMAP) LoadImage (NULL, L"Images/test_player_purple.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP background_bitmap = (HBITMAP) LoadImage (NULL, L"Images/test_background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC hdc = GetDC (Window);
HDC hdc_temp = CreateCompatibleDC (hdc);
HBITMAP bitmap_buffer = CreateCompatibleBitmap (hdc, resize.screen_width, resize.screen_height);
SelectObject (hdc, bitmap_buffer);
来自 wWinMain() 的主循环:
while (!Exit)
{
while (PeekMessage (&msg, nullptr, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
Render ();
}
调整大小完成的回调函数:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SIZE:
RECT window_rect;
if (GetWindowRect (Window, &window_rect))
{
hdc = GetDC (Window);
hdc_temp = CreateCompatibleDC (hdc);
bitmap_buffer = CreateCompatibleBitmap (hdc, resize.screen_width, resize.screen_height);
SelectObject (hdc, bitmap_buffer);
screen_width = window_rect.right - window_rect.left;
screen_height = window_rect.bottom - window_rect.top;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
实际通过BitBlt()渲染:
void Render ()
{
SelectObject (hdc_temp, background_bitmap);
BitBlt (hdc, 0, 0, 800, 600, hdc_temp, 0, 0, SRCCOPY);
SelectObject (hdc_temp, player_blue);
BitBlt (hdc, 0, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
SelectObject (hdc_temp, player_orange);
BitBlt (hdc, 126, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
SelectObject (hdc_temp, player_purple);
BitBlt (hdc, 252, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
}
正如 Ken 所说,您正在泄露宝贵的 GDI 资源。再调整一些大小,您的 window 可能会全黑 :)
请参阅https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc :
When you no longer need the memory DC, call the DeleteDC function.
您可能不需要在每次调整大小时都创建该 DC。
CreateCompatibleBitmap
也是如此。
我一直在 Visual C++ 中处理位图和渲染,遇到了一个奇怪的问题。
我正在尝试让绘图区域在用户调整 window 大小时调整大小。现在,不仅扩大 window 不会扩大可见绘图区域(白色边框出现在原始 window 边界之外),而且更改 window 大小似乎很麻烦用我的位图。
这是游戏启动时的样子:
更改 window 的宽度或高度后,紫色字符现在已被橙色字符替换。
最后,三个都变成了蓝色。
如果我继续下去,所有字符都会被绿草背景位图覆盖。
它似乎以位图呈现的相反顺序发生。添加第二行字符确认它在呈现代码中不是问题 - 内存中的实际位图正在以某种方式改变。删除调整大小代码会导致位图错误停止重现。
当我尝试重新初始化设备上下文时,几乎可以肯定这是我的调整大小代码中的一个错误,但我不确定它是什么。
这里是相关的设置代码:
HBITMAP player_blue = (HBITMAP) LoadImage (NULL, L"Images/test_player_blue.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP player_orange = (HBITMAP) LoadImage (NULL, L"Images/test_player_orange.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP player_purple = (HBITMAP) LoadImage (NULL, L"Images/test_player_purple.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP background_bitmap = (HBITMAP) LoadImage (NULL, L"Images/test_background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC hdc = GetDC (Window);
HDC hdc_temp = CreateCompatibleDC (hdc);
HBITMAP bitmap_buffer = CreateCompatibleBitmap (hdc, resize.screen_width, resize.screen_height);
SelectObject (hdc, bitmap_buffer);
来自 wWinMain() 的主循环:
while (!Exit)
{
while (PeekMessage (&msg, nullptr, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
Render ();
}
调整大小完成的回调函数:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SIZE:
RECT window_rect;
if (GetWindowRect (Window, &window_rect))
{
hdc = GetDC (Window);
hdc_temp = CreateCompatibleDC (hdc);
bitmap_buffer = CreateCompatibleBitmap (hdc, resize.screen_width, resize.screen_height);
SelectObject (hdc, bitmap_buffer);
screen_width = window_rect.right - window_rect.left;
screen_height = window_rect.bottom - window_rect.top;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
实际通过BitBlt()渲染:
void Render ()
{
SelectObject (hdc_temp, background_bitmap);
BitBlt (hdc, 0, 0, 800, 600, hdc_temp, 0, 0, SRCCOPY);
SelectObject (hdc_temp, player_blue);
BitBlt (hdc, 0, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
SelectObject (hdc_temp, player_orange);
BitBlt (hdc, 126, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
SelectObject (hdc_temp, player_purple);
BitBlt (hdc, 252, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
}
正如 Ken 所说,您正在泄露宝贵的 GDI 资源。再调整一些大小,您的 window 可能会全黑 :)
请参阅https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc :
When you no longer need the memory DC, call the DeleteDC function.
您可能不需要在每次调整大小时都创建该 DC。
CreateCompatibleBitmap
也是如此。