Opengl纹理有时会在窗口调整大小时闪烁/移动

时间:2018-03-28 12:08:54

标签: c++ winapi opengl

我有点问题。

我有一个带OpenGL子窗口的窗口, 到目前为止,所有Opengl窗口都会在窗口的右下角呈现纹理。

如果我从左到右快速调整窗口的大小,纹理有时会向左移动,就像它不能快速重新绘制,甚至知道我直接绘制到opengl上下文。

我删除问题的唯一方法是在主窗口调整大小时对opengl窗口的InvalidateRect,但我不知道为什么修复这个问题,因为我正在绘制到opengl上下文所以我不需要让它自己画出来之后我已经描绘了上下文。

如果bHandled为false,则调用defWndProc,否则返回函数

主窗口WM_SIZE

int ControllerMainWnd::OnSize(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
    bHandled = true;

    int width = LOWORD(lParam);
    int height = HIWORD(lParam);

    //Set OpenGL Window Size
    ::SetWindowPos(glHandle, 0, 0, 0, width, height, SWP_NOZORDER);

    //Invalidate OpenGL Window
    ::InvalidateRect(glHandle, 0, FALSE); // if i comment this out my texture sometime moves

    return 0;
}

OpenGL窗口

int ControllerGL::OnPaint(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
    //bHandled = true;
    //LRESULT lRes = defWinProc(WM_PAINT, wParam, lParam);

    Paint();

    //return lRes;
    return 0;
}

int ControllerGL::OnSize(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
    bHandled = true;

    int width = LOWORD(lParam);
    int height = HIWORD(lParam);

    modelGL->setWindowSize(width, height);

    Paint();

    return 0;
}

int ControllerGL::OnEraseBkgnd(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
    bHandled = true;
    return 1L;
}

auto ControllerGL::Paint() -> void
{
    openGLcontext->activateContext();
    modelGL->draw();
    openGLcontext->swapBuffers();
}

1 个答案:

答案 0 :(得分:1)

您的问题可能与以下事实有关:每次在调整大小期间移动鼠标时,都会导致窗口重新绘制2次。

首先,当您调整窗口区域时,Windows会自动使窗口区域无效(您可以使用应始终为OpenGL窗口设置的类样式CS_HREDRAW和CS_VREDRAW来控制它,因为调整大小通常需要完整窗口重绘)。

然后你(冗余地)手动使窗口rect无效。然后你强制它绘画 - 现在排队的未来油漆。

OpenGL窗口的OnPaint处理程序应该看起来像:

int ControllerGL::OnPaint(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd,&ps);
    wglMakeCurrent(hdc,hglrc);
    scene->Display();
    SwapBuffers(hdc);
    wglMakeCurrent(hdc,NULL);
    EndPaint(hwnd,&ps);
    bHandled = true;
    return 0;
}

我将它作为练习来正确封装hwnd和hglrc,以这种方式编写它会明确地显示SwapBuffers在DC上运行,而不是在隐式OpenGL上下文中运行,并且wglMakeCurrent应该使用动态获取的窗口作用域DC。

大多数OpenGL样本非常非常懒,并且使用类DC并且只是让openGL内容一直“活动”,但是一旦线程上的两个窗口试图执行OpenGL,这将会失败。最好省略CS_OWNDC(如果有的话)并在实际需要时获取(和释放)DC。

即。如果你想更传统地处理WM_SIZE(类似于glut Reshape回调)你会这样做:

int ControllerGL::OnSize(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
    bHandled = true;

    int width = LOWORD(lParam);
    int height = HIWORD(lParam);

    HDC hdc = GetDC(hwnd);
    wglMakeCurrent(hdc,hglrc);

    scene->Reshape(width,height);

    wglMakeCurrent(hdc,NULL);
    ReleaseDC(hwnd,hdc);
    return 0;
}

ControllerGL到我称之为scene的所有其他来电,您致电modelGL同样会被包裹。