如何使用 WinAPI 每帧仅重绘一次 child window?
How to repaint a child window only once every frame using WinAPI?
我正在使用 Direct3D 和 WinAPI 在客户区创建 windows 和渲染 3D objects。我使用标准 Windows 消息循环使渲染 window 的矩形无效,并且在渲染 window 的消息处理程序中,我在处理 [= 时在 Direct3D 中执行渲染调用13=] 消息:
BOOL bRet;
HWND mainWnd; // Main window
HWND renderWnd; // Child of mainWnd, takes up a portion of the client area
// to be used as a Direct3D render target
MSG msg = {};
while ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if(bRet != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
InvalidateRect(renderWnd, nullptr, false);
}
}
// ...
// Window procedure used by renderWnd
LRESULT renderWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// ...
case WM_PAINT:
{
// Perform Direct3D rendering
// ...
}
break;
// ...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
只要我的应用程序只有一个 window,此设置似乎就可以正常工作,因为每个帧都会调用 InvalidateRect
并确保需要重绘客户区,而这又会导致 Direct3D 绘图调用。虽然感觉不是很优雅,尤其是当我尝试创建多个 windows 时,因为我必须在同一段代码中使它们的矩形无效,即使 windows 提供的功能也是如此否则彼此无关(某些 windows 甚至可能在任何时候都不存在)。
就是说,我的问题是:是否可以让 window 使其客户区的一部分在每一帧 恰好一次 无效(假设它当前未最小化) , ETC。)?也许通过使用消息队列?回顾上面的代码段:我想要一些方法让 mainWnd
(也许在它自己的 window 过程中)在每帧恰好在 renderWnd
上调用 InvalidateRect
一次。
提前致谢!
编辑:代码示例中的小错误
所以在对原始 post 的评论的帮助下,我发现最好的选择是使用 WinAPI 提供的 Timers 来安排渲染的重绘 window 以所需的帧速率。将其标记为已解决。
请注意,'standard' 处理此问题的方法更像是这样:
// Main message loop
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Update your simulation/animation/etc. based on elapsed time
// -or-
// multiple fixed time-steps.
//
// Then render one frame.
}
}
…
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
此模型是一个 'flat-out' 渲染模型,您将在其中尽可能快地渲染系统,如果您有 3 个或更多帧,则受 Present
刷新率和自动节流等细节的限制准备好了。
You should take a look at GitHub for some more details like implementing WM_ENTERSIZEMOVE
/ WM_EXITSIZEMOVE
.
你唯一需要实现 WM_PAINT
/ InvalidateRect
渲染的情况是你正在做一个编辑器或一些 'mixed' UI 和 Direct3D 应用程序。
我正在使用 Direct3D 和 WinAPI 在客户区创建 windows 和渲染 3D objects。我使用标准 Windows 消息循环使渲染 window 的矩形无效,并且在渲染 window 的消息处理程序中,我在处理 [= 时在 Direct3D 中执行渲染调用13=] 消息:
BOOL bRet;
HWND mainWnd; // Main window
HWND renderWnd; // Child of mainWnd, takes up a portion of the client area
// to be used as a Direct3D render target
MSG msg = {};
while ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if(bRet != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
InvalidateRect(renderWnd, nullptr, false);
}
}
// ...
// Window procedure used by renderWnd
LRESULT renderWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// ...
case WM_PAINT:
{
// Perform Direct3D rendering
// ...
}
break;
// ...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
只要我的应用程序只有一个 window,此设置似乎就可以正常工作,因为每个帧都会调用 InvalidateRect
并确保需要重绘客户区,而这又会导致 Direct3D 绘图调用。虽然感觉不是很优雅,尤其是当我尝试创建多个 windows 时,因为我必须在同一段代码中使它们的矩形无效,即使 windows 提供的功能也是如此否则彼此无关(某些 windows 甚至可能在任何时候都不存在)。
就是说,我的问题是:是否可以让 window 使其客户区的一部分在每一帧 恰好一次 无效(假设它当前未最小化) , ETC。)?也许通过使用消息队列?回顾上面的代码段:我想要一些方法让 mainWnd
(也许在它自己的 window 过程中)在每帧恰好在 renderWnd
上调用 InvalidateRect
一次。
提前致谢!
编辑:代码示例中的小错误
所以在对原始 post 的评论的帮助下,我发现最好的选择是使用 WinAPI 提供的 Timers 来安排渲染的重绘 window 以所需的帧速率。将其标记为已解决。
请注意,'standard' 处理此问题的方法更像是这样:
// Main message loop
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Update your simulation/animation/etc. based on elapsed time
// -or-
// multiple fixed time-steps.
//
// Then render one frame.
}
}
…
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
此模型是一个 'flat-out' 渲染模型,您将在其中尽可能快地渲染系统,如果您有 3 个或更多帧,则受 Present
刷新率和自动节流等细节的限制准备好了。
You should take a look at GitHub for some more details like implementing
WM_ENTERSIZEMOVE
/WM_EXITSIZEMOVE
.
你唯一需要实现 WM_PAINT
/ InvalidateRect
渲染的情况是你正在做一个编辑器或一些 'mixed' UI 和 Direct3D 应用程序。