Ste*_* Lu 11 c++ opengl winapi sdl
首先,我的代码设置了SDL环境,然后继续更新OpenGL上下文,而不执行任何SDL_Event处理.这会导致窗口在打开时对Windows显示无响应.窗口闪烁了一下.标题栏将附加"(无响应)",并且在窗口内单击时,它将变为灰色,因为Windows在非响应窗口上默认执行此操作.然而,在这种状态下(即使在它变灰之后),OpenGL显示继续更新和动画,这里是踢球者,它甚至在拖动窗口时这样做.显然,在这种情况下,应用程序不会正确处理来自窗口的事件,导致窗口认为它处于挂起状态.但有明显的证据表明,opengl仍在继续呈现.
现在我对代码进行一次修改,这三行放在循环内的适当位置(也可以进行OpenGL绘制):
SDL_Event event;
if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
break;
Run Code Online (Sandbox Code Playgroud)
所有这一切都是使用SDL刷新消息队列.
现在的行为是Windows不再认为它是"无响应"并且它不会变灰.没有闪烁.一切似乎都在游泳.但是,一旦我单击并拖动标题栏拖动窗口,渲染就会被阻止.我没有调试它以确定,但我怀疑SDL_PollEvent阻止窗口拖动的持续时间.
有没有解决的办法?这很有趣,因为未能处理事件所表现出的部分行为证明我理想的是可能的.
更新:我找到了这个主题:http://www.gamedev.net/topic/488074-win32-message-pump-and-opengl---rendering-pauses-while-draggingresizing/
判决结果似乎归结为微软为我们做出的某些选择......它基本上陷入困境DefWindowProc()直到鼠标被释放.破解修复程序会变得非常混乱,我可能可以通过在另一个线程中渲染来解决问题.但我甚至不想开始考虑从多个线程中处理OpenGL上下文,如果这甚至是可能的话.
一些对我有用的解决方法 - 为 SDL_WINDOWEVENT_SIZE_CHANGED 事件添加事件过滤器,并执行额外的 SetViewport 和绘制框架。
int SDLApp::eventFilter(void* pthis, const SDL_Event *event)
{
if (event->type == SDL_WINDOWEVENT &&
event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
SDLApp* app = (SDLApp*)pthis;
// Note: NULL rectangle is the entire window
SDL_RenderSetViewport(app->renderer_, NULL);
app->DrawFrame();
}
return 1;
}
...
SDL_SetEventFilter((SDL_EventFilter)SDLApp::eventFilter, this);
Run Code Online (Sandbox Code Playgroud)
这个问题很旧,但我正在使用的解决方案似乎没有在其他地方提到,所以在这里。
我从这个答案中得到了灵感,它不使用额外的线程。
#include <SDL.h>
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <SDL_syswm.h>
#define SIZE_MOVE_TIMER_ID 1
bool sizeMoveTimerRunning = false;
int eventWatch(void*, SDL_Event* event) {
if (event->type == SDL_SYSWMEVENT) {
const auto& winMessage = event->syswm.msg->msg.win;
if (winMessage.msg == WM_ENTERSIZEMOVE) {
// the user started dragging, so create the timer (with the minimum timeout)
// if you have vsync enabled, then this shouldn't render unnecessarily
sizeMoveTimerRunning = SetTimer(GetActiveWindow(), SIZE_MOVE_TIMER_ID, USER_TIMER_MINIMUM, nullptr);
}
else if (winMessage.msg == WM_TIMER) {
if (winMessage.wParam == SIZE_MOVE_TIMER_ID) {
// call your render function
render();
}
}
}
return 0;
}
// rendering function
void render() {
/* do your rendering here */
}
// event loop - call this function after setting up your window to start the event loop
void eventLoop() {
SDL_AddEventWatch(eventWatch, nullptr); // register the event watch function
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); // we need the native Windows events, so we can listen to WM_ENTERSIZEMOVE and WM_TIMER
while (true) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (sizeMoveTimerRunning) {
// modal drag/size loop ended, so kill the timer
KillTimer(GetActiveWindow(), SIZE_MOVE_TIMER_ID);
sizeMoveTimerRunning = false;
}
/* handle the events here */
}
render();
}
}
Run Code Online (Sandbox Code Playgroud)
当然,如果您的渲染函数需要保留额外的状态(例如,如果您使用 OOP),请使用void*参数eventWatch(void*, SDL_Event*)来传递状态。
我建议你创建 2 个线程:
这样,您的 OpenGL 上下文就可以通过单个线程进行操作。整个解决方案对应用程序架构的影响最小。
| 归档时间: |
|
| 查看次数: |
5264 次 |
| 最近记录: |