【发布时间】:2010-10-09 20:01:37
【问题描述】:
我目前正在尝试将我的一些动画绘制代码以外部插件的形式集成到第三方应用程序中。
这个基于 OpenGL 的实时 3d 动画代码,应该尽可能快地渲染,通常每秒 60 帧。
在我是世界之王的基础应用程序中,我控制应用程序消息泵,以便尽可能进行绘制。像这样:
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
do
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
}
draw();
}
现在我不再是世界上的王者,我必须好好处理应用程序消息,以便它保持响应。据我所知,由于我是一个插件,我无法劫持整个应用程序消息泵;所以我尝试了各种方法,在 WM_PAINT 消息处理程序中进行绘图:
WM_TIMER,这不起作用:我事先不知道我需要哪个时间步长(通常不固定)并且时间不准确。
InvalidateRect,但不起作用:完全阻止应用程序的其余部分响应并自行刷新。
InvalidateRect(请参阅there)。
到目前为止,我的最后一次尝试是更好的,有时工作正常。
DWORD WINAPI PaintCommandThreadProc(LPVOID lpParameter)
{
Plugin* plugin = static_cast<Plugin*>(lpParameter);
HANDLE updateEvent = plugin->updateEvent();
while (updateEvent == plugin->updateEvent())
{
::WaitForSingleObject(updateEvent, 100);
::Sleep(0);
if (updateEvent == plugin->updateEvent())
{
::PostMessage(plugin->hwnd(), WM_USER+0x10, 0, 0);
}
}
return 0;
}
...
LRESULT CALLBACK PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
bool processDefault = true;
LRESULT result = 0;
Plugin* plugin = reinterpret_cast<Plugin*>( GetWindowLong(hWnd, GWL_USERDATA) );
switch (msg) {
...
case WM_GL_MESSAGE:
{
::InvalidateRect( hWnd, NULL, FALSE );
processDefault = false;
result = TRUE;
}
break;
case WM_PAINT:
{
draw(hWnd);
::SetEvent( plugin->updateEvent() );
processDefault = false;
result = TRUE;
}
break;
...
}
if (processDefault && plugin && plugin->m_wndOldProc)
result = ::CallWindowProc(plugin->m_wndOldProc, hWnd, msg, wParam, lParam);
return result;
}
在某些情况下,主机应用程序似乎仍会丢失消息。该问题的主要特征是我必须按“Alt”键才能显示模式对话框;我必须移动鼠标给主机应用程序一些处理时间!...
是否有任何“行业标准”解决方案可以解决这种“尽可能频繁”的动画重绘问题?
【问题讨论】:
标签: c winapi graphics animation