1
votes

I write a OpenGL code for Render Images on screen. I using GLUT to create a window and callbacks but i want to render images in win32 window not in the GLUT, basically we have a CreateWindowEx() API to create window in win32 and we have a HWND(handle) so that we can pass this handle to HDCbut i didn't find anything like this in GLUT, is it possible to send handle to GLUT ? or other approach ?.

Below is my code its render images on screen successfully.

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();
}
1
glut uses a win32 window. If you mean that you want to create your own window, then you can't use glut. This and this are good starting points.BDL
wglCreateContext is the name of a function you'll need. You'll also need to understand that GLUT usual stands between you and openGL. With that intermediary gone, you'll need to work a lot harder to achieve the same thing yourself without the help of many functions often taken for granted. Perhaps you'll find some use in solution #2 over here: codeproject.com/questions/672673/…enhzflep
@BDL I already have a win32 window and with a menu items too but i started with glut to create a window and render images successfully now just i want to replace my render window to the win32 window. can we pass HWND handle to glut ?Krish
You can't. glut is way more than just a OpenGL context creation tool. It also deals with resizing, input and many more things and controlls the whole messaging system of the window. If you want to use glut, then you have to use the glut window. If you want a custom window, you have to create the context yourself (or use another library that can create an OpenGL context in an existing window).BDL
I think it will be possible withe wglCreateContext it takes HDC. Thank you both @enhzflep and @BDL.Krish

1 Answers

4
votes

If you want to create a win32 OpenGL window, without any window library, the you have to do the following:

#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;
}

For the window a procedure is neede, which handles the window messages:

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 );
}

The main loop has to get an dispatch the window messages (message loop):

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

The window can be destroied like this:

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 );
}

For the seeness of completeness a simple demo program:

#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);
 }


Note, if you do not show the window (skip ShowWindow), the you have a hidden window where you can do image rendering. You can read a renderd image from the GPU by glReadPixels or you can create a framebuffer with a attached texture and read the texture by glGetTexImage.