В настоящее время я пытаюсь интегрировать некоторый мой код рисования анимации в стороннее приложение в виде внешнего плагина.
Этот код анимации в режиме реального времени 3d основан на OpenGL и должен отображаться с максимальной скоростью, обычно со скоростью 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
(см.
там ).
Пока что моя последняя попытка лучше, а иногда и работает нормально.
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» для отображения модальных диалогов; и я должен переместить мышь, чтобы дать некоторое время обработки хост-приложению! ...
Существует ли какое-либо «стандартное» решение для такой проблемы перерисовки анимации, как часто бывает? *