[ACCEPTED]-Multiple windows in OpenGL?-multi-window

Accepted answer
Score: 12

Yes, this is possible. For each window you 4 will need to create a unique device context 3 and render context.

HDC hDC = GetDC( hWnd ); /* get the device context for a particular window */
/* snip */
HGLRC hRC;
hRC = wglCreateContext( hDC ); /* get a render context for the same window */
/* repeat with hDC2 and hRC2 with another window handle*/

Before making GL calls 2 to the window you must call wglMakeCurrent 1 like this:

wglMakeCurrent( hDC, hRC );
/* GL calls for first window */
wglMakeCurrent( NULL, NULL);

wglMakeCurrent( hDC2, hRC2 );
/* GL calls for second window */
wglMakeCurrent( NULL, NULL);
Score: 11

If you're using GLUT you can use the glutSetWindow() / glutGetWindow() calls 26 to select the correct window (after creating 25 them with glutCreateSubWindow()). However 24 sometimes GLUT might not be the right tool 23 for the job.

If you're working on Windows 22 you'll want to look into the wglMakeCurrent() and 21 wglCreateContext(). On OS X there is aglSetCurrentContext() et 20 cetera, and X11 requires glXMakeCurrent().

Those 19 functions activate the current OpenGL context 18 to which you can render. Each platform specific 17 library has it's own ways of creating a 16 window and binding an OpenGL context to 15 it.

On Windows, after you've acquired your 14 HWND and HDC for a window (after a CreateWindow 13 and GetDC call). You generally do something 12 like this to set up OpenGL:

GLuint l_PixelFormat = 0;

// some pixel format descriptor that I generally use:
static PIXELFORMATDESCRIPTOR l_Pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, 
    PFD_DRAW_TO_WINDOW + PFD_SUPPORT_OPENGL + PFD_DOUBLEBUFFER, 
    PFD_TYPE_RGBA, m_BitsPerPixel, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0};

if(!(l_PixelFormat = ChoosePixelFormat(m_hDC, &l_Pfd))){
    throw std::runtime_error("No matching pixel format descriptor");
}

if(!SetPixelFormat(m_hDC, l_PixelFormat, &l_Pfd)){
    throw std::runtime_error("Can't set the pixel format");
}

if(!(m_hRC = wglCreateContext(m_hDC))){
    throw std::runtime_error("Can't create rendering context");
}

wglMakeCurrent(m_hDC, m_hRC);

You use that 11 code to create multiple windows and bind 10 OpenGL to it, then each time you want to 9 draw to a specific window you have to call 8 wglMakeCurrent before you do anything and you 7 pass in the parameters corresponding to 6 that window.

As a side-note, OpenGL allows 5 you to share certain data between different 4 contexts, however as per spec the data that 3 you can share is pretty limited. However, most 2 OSes allow you to share more data than specified 1 in the specification.

Score: 5

On Windows you can share OpenGL objects 3 such as textures and shaders with wglShareLists(). It typically 2 does share everything you'd care about, despite 1 what MSDN says.

Score: 1

I've done multiple OpenGL windows in an 10 MFC application before. Here's a class you 9 might find useful: since there can only 8 be one current render context in the UI 7 thread at a time, I wrote a class wrapper 6 to make managing it easier.

SaveRestoreRC.h

// this class helps to manage multiple RCs using an RAII design pattern

class CSaveRestoreRC
{
public:
HDC   oldDC;            
HGLRC oldRC;            

CSaveRestoreRC(HDC hDC, HGLRC hRC);
~CSaveRestoreRC(void);
};

SaveRestoreRC.cpp:

CSaveRestoreRC::CSaveRestoreRC(HDC hDC, HGLRC hRC)
{
ASSERT( hDC );
ASSERT( hRC );

oldDC = wglGetCurrentDC();
oldRC = wglGetCurrentContext();

BOOL result = wglMakeCurrent( hDC, hRC );
ASSERT( result );
}

CSaveRestoreRC::~CSaveRestoreRC(void)
{
if( !oldRC )
    return;
ASSERT( oldDC );
BOOL result = wglMakeCurrent( oldDC, oldRC );
ASSERT( result );    
}

Now 5 derive a class from CWnd and add these member 4 variables:

class COpenGLControl : public CWnd
{
    // used to interface OpenGL with Windows
    HDC   hdc;          
    HGLRC hrc;          
// ...

int COpenGLControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
    return -1;
// Get device context only once.
hdc = GetDC()->m_hDC;

// ... ChoosePixelFormat, SetPixelFormat, etc. here.

// Create the OpenGL Rendering Context.
hrc = wglCreateContext(hdc);
ASSERT( hrc );

Then in every member function 3 where you call ANY OpenGL commands, use 2 CSaveRestoreRC so that your current render 1 context doesn't get screwed up.

void COpenGLControl::UpdateCamera()
{
CSaveRestoreRC c(hdc, hrc);

// Map the OpenGL device coordinates.
glViewport(0, 0, renderingWindow.Width(), renderingWindow.Height());

// Do your other OpenGL stuff here
// ... 

// the CSaveRestoreRC destructor will automatically put the correct render context back, 
// even if you call other functions. Of course, put another CSaveRestoreRC there too.
} 

More Related questions