【问题标题】:Render image using OpenGL in win32 window在 win32 窗口中使用 OpenGL 渲染图像
【发布时间】:2018-05-28 07:14:30
【问题描述】:

我为在屏幕上渲染图像编写了OpenGL 代码。我使用GLUT 创建一个窗口和回调,但我想在win32 窗口中而不是在GLUT 中渲染图像,基本上我们有一个CreateWindowEx() API 在win32 中创建窗口,我们有一个@987654330 @(handle) 以便我们可以将此句柄传递给HDC,但我在GLUT 中没有找到类似的东西,是否可以将句柄发送给GLUT ?或其他方法?

下面是我的代码,它成功地在屏幕上渲染图像。

int main()
{       
    __try{    
        int argc = 1;
        char *argv[1] = { (char*)"GLUTwindow" };
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
        glutInitWindowSize(1024, 768);
        glutInitWindowPosition(0, 0);
        glutCreateWindow("GLUTwindow");
        GLenum err = glewInit(); if (GLEW_OK != err)                                                        __debugbreak();
        init();
        glutDisplayFunc(display);
        glutReshapeFunc(reshape);
        glutMotionFunc(motion);
        glutMainLoop();         
    }
    __except (EXCEPTION_EXECUTE_HANDLER) 
    {

    }
    return 0;
}

void init()
{
    // compile and link the shaders into a program, make it active
    vShader = compileShader(vertexShader, GL_VERTEX_SHADER);
    fShader = compileShader(fragmentShader, GL_FRAGMENT_SHADER);
    std::list<GLuint> tempList;
    tempList.clear();
    tempList.insert(tempList.end(), (GLuint)vShader);
    tempList.insert(tempList.end(), (GLuint)fShader);
    program = createProgram(tempList);
    offset = glGetUniformLocation(program, "offset");                                           GLCHK;
    texUnit = glGetUniformLocation(program, "texUnit");                                         GLCHK;
    glUseProgram(program);                                                                      GLCHK;

    // configure texture unit
    glActiveTexture(GL_TEXTURE0);                                                               GLCHK;
    glUniform1i(texUnit, 0);                                                                    GLCHK;

    // create and configure the textures
    glGenTextures(1, &texture);                                                                 GLCHK;
    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, texture);                                                      GLCHK;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);                               GLCHK;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);                               GLCHK;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);                          GLCHK;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);                          GLCHK;

}


    void display()
{   
    GLuint w, h;  std::vector<GLubyte> img; if (lodepng::decode(img, w, h, "test2.png"))    __debugbreak();
    glBindTexture(GL_TEXTURE_2D, texture);                                                      GLCHK;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,w,h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &img[0]); GLCHK;    
    glClear(GL_COLOR_BUFFER_BIT);                                                               GLCHK;
    glBindTexture(GL_TEXTURE_2D, texture);                                                      GLCHK;
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);                                                      GLCHK;
    glutSwapBuffers();      
    glutPostRedisplay();
}

【问题讨论】:

  • glut 使用 win32 窗口。如果您的意思是要创建自己的窗口,则不能使用 glut。 Thisthis 是很好的起点。
  • wglCreateContext 是您需要的函数的名称。您还需要了解 GLUT 通常介于您和 openGL 之间。随着中介的消失,您将需要更加努力地自己实现相同的目标,而无需借助许多通常被认为是理所当然的功能。也许您会在此处的解决方案 #2 中找到一些用处:codeproject.com/questions/672673/…
  • @BDL 我已经有一个 win32 窗口和一个菜单项,但是我从 glut 开始创建一个窗口并成功渲染图像,现在我只想将我的渲染窗口替换为 win32 窗口。我们可以将 HWND 句柄传递给 glut 吗?
  • 你不能。 glut 不仅仅是一个 OpenGL 上下文创建工具。它还处理调整大小、输入和更多的事情,并控制窗口的整个消息传递系统。如果要使用 glut,则必须使用 glut 窗口。如果你想要一个自定义窗口,你必须自己创建上下文(或者使用另一个可以在现有窗口中创建 OpenGL 上下文的库)。
  • 我认为 wglCreateContext 可以使用 HDC。谢谢@enhzflep 和@BDL。

标签: c++ winapi opengl


【解决方案1】:

如果你想创建一个win32 OpenGL窗口,没有任何窗口库,你必须执行以下操作:

#include <GL/gl.h>
#include <windows.h>

const std::wstring wnd_class( L"my_wnd_class" );
HWND hOGLWnd = NULL;
HGLRC hOGLRenderContext = NULL;

HWND createWindow( int width, int height )
{
    // Get module handle
    HMODULE hModule = ::GetModuleHandle( 0 );
    if (!hModule)
        return NULL;

    // Create window calss
    WNDCLASSEX wndClassData;
    memset( &wndClassData, 0, sizeof( WNDCLASSEX ) );
    wndClassData.cbSize         = sizeof( WNDCLASSEX );
    wndClassData.style          = CS_DBLCLKS;
    wndClassData.lpfnWndProc    = WindowProcedure;
    wndClassData.cbClsExtra     = 0;
    wndClassData.cbWndExtra     = 0;
    wndClassData.hInstance      = hModule;
    wndClassData.hIcon          = ::LoadIcon(0,IDI_APPLICATION);
    wndClassData.hCursor        = ::LoadCursor(0,IDC_ARROW);
    wndClassData.hbrBackground  = ::CreateSolidBrush(COLOR_WINDOW+1);
    wndClassData.lpszMenuName   = 0;
    wndClassData.lpszClassName  = wnd_class.c_str();
    wndClassData.hIconSm        = 0;
    if ( !::RegisterClassEx( &wndClassData ) )
        return false;

    // Creaate Window
    hOGLWnd = ::CreateWindow( wnd_class.c_str(), NULL, WS_OVERLAPPEDWINDOW, 0, 0, width, height, NULL, NULL, hModule, NULL);
    if ( hOGLWnd == NULL )
        return NULL;

    // Get device context
    HDC hDC = ::GetDC( hOGLWnd );

    // Create OpenGL context
    DWORD pixelFormatFlags = PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION | PFD_GENERIC_ACCELERATED | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
    PIXELFORMATDESCRIPTOR pfd =
    {
      sizeof(PIXELFORMATDESCRIPTOR),
      1,
      pixelFormatFlags,         //Flags
      PFD_TYPE_RGBA,            //The kind of framebuffer. RGBA or palette.
      32,                       //Colordepth of the framebuffer.
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      24,                       //Number of bits for the depthbuffer
      8,                        //Number of bits for the stencilbuffer
      0,                        //Number of Aux buffers in the framebuffer.
      PFD_MAIN_PLANE,
      0, 0, 0, 0
    };
    int pixelFormat = ::ChoosePixelFormat( hDC, &pfd ); 
    ::SetPixelFormat( hDC, pixelFormat, &pfd );
    hOGLRenderContext = ::wglCreateContext( hDC );

    // make OpenGL context the current context
    ::wglMakeCurrent( hDC, hOGLRenderContext );

    // release device context
    ::ReleaseDC( hOGLWnd, hDC );

    // show the window
    ::ShowWindow( hOGLWnd, SW_SHOWDEFAULT );
    return hOGLWnd;
}

对于窗口来说,需要一个过程来处理窗口消息:

LRESULT CALLBACK WindowProcedure( HWND hWnd, unsigned int msg, WPARAM wparam, LPARAM lparam )
{
    switch(msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_ERASEBKGND: 
        display();
        break;
    }
    return DefWindowProc( hWnd, msg, wparam, lparam );
}

主循环必须得到一个dispatch窗口消息(消息循环):

void mainloop( void )
{
    MSG msg;
    while( ::GetMessage( &msg, 0, 0, 0 ) )
        ::DispatchMessage( &msg );
}

窗口可以这样销毁:

void destroyWindow(void)
{
    if ( HDC currentDC = ::wglGetCurrentDC() )
        ::wglMakeCurrent( currentDC , NULL );
    ::DestroyWindow( hOGLWnd );
    ::wglDeleteContext( hOGLRenderContext );

    HMODULE hModule = ::GetModuleHandle( 0 );
    if (!hModule)
        return;
    ::UnregisterClass( wnd_class.c_str(), hModule );
}

为了完整起见,一个简单的演示程序:

#include <GL/glew.h>
#include <vector>
#include <stdexcept>

int main()
{
    int w = 800;
    int h = 600;

    HWND hWnd = createWindow( w, h );
    if ( hWnd == 0 )
        throw std::runtime_error( "error initializing window" ); 

    if ( glewInit() != GLEW_OK )
        throw std::runtime_error( "error initializing glew" );

    static const std::vector<float> varray
    { 
      -0.707f, -0.75f,    1.0f, 0.0f, 0.0f, 1.0f, 
       0.707f, -0.75f,    1.0f, 1.0f, 0.0f, 1.0f,
       0.0f,    0.75f,    0.0f, 0.0f, 1.0f, 1.0f
    };

    GLuint vbo;
    glGenBuffers( 1, &vbo );
    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, varray.size()*sizeof(*varray.data()), varray.data(), GL_STATIC_DRAW );

    GLuint vao;
    glGenVertexArrays( 1, &vao );
    glBindVertexArray( vao );
    glVertexPointer( 2, GL_FLOAT, 6*sizeof(*varray.data()), 0 );
    glEnableClientState( GL_VERTEX_ARRAY );
    glColorPointer( 4, GL_FLOAT, 6*sizeof(*varray.data()), (void*)(2*sizeof(*varray.data())) ); 
    glEnableClientState( GL_COLOR_ARRAY );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    mainloop();    
    destroyWindow();
    return 0;
}

void display( void )
{
    RECT clientRect;
      ::GetClientRect( hOGLWnd, &clientRect );
    glViewport( 0, 0, clientRect.right-clientRect.left, clientRect.bottom-clientRect.top );
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);    

    glDrawArrays( GL_TRIANGLES, 0, 3 );

    // swap buffers
    HDC hDC = ::GetDC( hOGLWnd );
    ::SwapBuffers( hDC );
    ::ReleaseDC( hOGLWnd, hDC );

    // create message WM_ERASEBKGND
    ::InvalidateRect( hOGLWnd, NULL, TRUE);
 }


请注意,如果您不显示窗口(跳过ShowWindow),则您有一个隐藏窗口,您可以在其中进行图像渲染。您可以通过glReadPixels 从GPU 读取渲染图像,或者您可以创建带有附加纹理的帧缓冲区并通过glGetTexImage 读取纹理。

【讨论】:

    猜你喜欢
    • 2019-07-15
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多