OGL multiple render windows patch
Posted: Sat Mar 31, 2007 10:48 am
Hi,
for those interested, i've recently updated to Irrlicht 1.3 (svn rev 574) and therefore needed to update my patch-set. One of the patches i use deals with rendering to multiple output windows when using Open GL.
Please find the patch below:
The way nico is doing that thing with D3D does not work with OGL, i.e. handing over the window handle of the given window via endScene and then bind the device to a render context does not work, because all previously drawn things get lost. So the binding has to be done _before_ any drawing.
Therefore i needed to do a tiny extension of the driver-API, to be used like this:
driver->setRenderWindow((s32)GetHandle());
driver->beginScene(true, true, SColor(100, 100, 100, 100));
// ...do some drawing here
driver->endScene();
It's only implemented for the win code path at the moment.
thx for commenting!
bye mrc
for those interested, i've recently updated to Irrlicht 1.3 (svn rev 574) and therefore needed to update my patch-set. One of the patches i use deals with rendering to multiple output windows when using Open GL.
Please find the patch below:
Code: Select all
diff -uBb -x .cbp Irrlicht.svn/CNullDriver.cpp Irrlicht/CNullDriver.cpp
--- Irrlicht.svn/CNullDriver.cpp Tue Mar 27 12:00:41 2007
+++ Irrlicht/CNullDriver.cpp Sat Mar 31 09:50:29 2007
@@ -197,6 +197,11 @@
}
+bool CNullDriver::setRenderWindow(s32 windowId)
+{
+ return true;
+}
+
//! applications must call this method after performing any rendering. returns false if failed.
bool CNullDriver::endScene( s32 windowId, core::rect<s32>* sourceRect )
diff -uBb -x .cbp Irrlicht.svn/CNullDriver.h Irrlicht/CNullDriver.h
--- Irrlicht.svn/CNullDriver.h Tue Mar 27 12:00:37 2007
+++ Irrlicht/CNullDriver.h Sat Mar 31 09:50:03 2007
@@ -35,6 +35,8 @@
virtual bool beginScene(bool backBuffer, bool zBuffer, SColor color);
+ virtual bool setRenderWindow(s32 windowId);
+
virtual bool endScene( s32 windowId = 0, core::rect<s32>* sourceRect=0 );
//! queries the features of the driver, returns true if feature is available
diff -uBb -x .cbp Irrlicht.svn/COpenGLDriver.cpp Irrlicht/COpenGLDriver.cpp
--- Irrlicht.svn/COpenGLDriver.cpp Tue Mar 27 12:00:40 2007
+++ Irrlicht/COpenGLDriver.cpp Sat Mar 31 10:11:20 2007
@@ -69,7 +69,28 @@
bool COpenGLDriver::initDriver(const core::dimension2d<s32>& screenSize,
HWND window, u32 bits, bool fullscreen, bool vsync)
{
- static PIXELFORMATDESCRIPTOR pfd = {
+ currentHDC = HDc = getGLContext(window, bits);
+ Window = window;
+ bpp = bits;
+
+ genericDriverInit(screenSize);
+
+ // set vsync
+ if (wglSwapIntervalEXT)
+ wglSwapIntervalEXT(vsync ? 1 : 0);
+
+ // set exposed data
+ ExposedData.OpenGLWin32.HDc = reinterpret_cast<s32>(HDc);
+ ExposedData.OpenGLWin32.HRc = reinterpret_cast<s32>(HRc);
+ ExposedData.OpenGLWin32.HWnd = reinterpret_cast<s32>(Window);
+
+ return true;
+}
+
+//! initializes a GL context for a given window ID
+HDC COpenGLDriver::getGLContext(HWND window, u32 bits)
+{
+ PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
@@ -90,87 +111,98 @@
0, 0, 0 // Layer Masks Ignored
};
+ if(glcontext.size() > 0 && window == Window)
+ {
+ if(currentHDC != HDc)
+ wglMakeCurrent(HDc, HRc);
+
+ return HDc;
+ }
+
+ struct SGLContext *glc = NULL;
+
+ for (u32 i=0; i<glcontext.size(); i++)
+ {
+ if(window == glcontext[i].hwnd)
+ {
+ glc = &glcontext[i];
+ wglMakeCurrent(glc->hdc, glc->ctx);
+ return glc->hdc;
+ }
+ }
+
+ glc = new SGLContext();
+ glc->hwnd = window;
+
for (int i=0; i<5; ++i)
{
if (i == 1)
{
- if (StencilBuffer)
os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING);
StencilBuffer = false;
pfd.cStencilBits = 0;
- }
- else
- if (i == 2)
- {
+ }else if (i == 2){
pfd.cDepthBits = 24;
}
if (i == 3) // might be checked twice, but shouldn't matter
{
pfd.cDepthBits = 16;
}
- else
- if (i == 4)
+ else if (i == 2)
{
os::Printer::log("Cannot create a GL device context.", ELL_ERROR);
- return false;
+ return 0;
}
// get hdc
- if (!(HDc=GetDC(window)))
+ if (!(glc->hdc=GetDC(window)))
{
os::Printer::log("Cannot create a GL device context.", ELL_ERROR);
continue;
}
- GLuint PixelFormat;
-
// choose pixelformat
- if (!(PixelFormat = ChoosePixelFormat(HDc, &pfd)))
+ if(glcontext.size() == 0)
+ {
+ if (!(PixelFormat = ChoosePixelFormat(glc->hdc, &pfd)))
{
os::Printer::log("Cannot find a suitable pixelformat.", ELL_ERROR);
continue;
}
+ }
// set pixel format
- if(!SetPixelFormat(HDc, PixelFormat, &pfd))
+ if(!SetPixelFormat(glc->hdc, PixelFormat, &pfd))
{
os::Printer::log("Cannot set the pixel format.", ELL_ERROR);
continue;
}
// create rendering context
- if (!(HRc=wglCreateContext(HDc)))
+ if(glcontext.size() == 0)
+ {
+ if (!(HRc=wglCreateContext(glc->hdc)))
{
os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR);
continue;
}
+ }
+
+ glc->ctx = HRc;
// activate rendering context
- if(!wglMakeCurrent(HDc, HRc))
+ if(!wglMakeCurrent(glc->hdc, glc->ctx))
{
os::Printer::log("Cannot activate GL rendering context", ELL_ERROR);
continue;
}
-
break;
}
-
- genericDriverInit(screenSize);
-
- // set vsync
- if (wglSwapIntervalEXT)
- wglSwapIntervalEXT(vsync ? 1 : 0);
-
- // set exposed data
- ExposedData.OpenGLWin32.HDc = reinterpret_cast<s32>(HDc);
- ExposedData.OpenGLWin32.HRc = reinterpret_cast<s32>(HRc);
- ExposedData.OpenGLWin32.HWnd = reinterpret_cast<s32>(Window);
-
- return true;
+ glcontext.push_back(*glc);
+ return glc->hdc;
}
-
//! win32 destructor
COpenGLDriver::~COpenGLDriver()
{
@@ -756,7 +788,23 @@
glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &MaxIndices);
}
+bool COpenGLDriver::setRenderWindow(s32 windowId)
+{
+ RECT r;
+
+ if(!windowId)
+ {
+ currentHDC = getGLContext(Window, bpp);
+ GetClientRect((HWND) Window, &r);
+ }else{
+ currentHDC = getGLContext((HWND) windowId, bpp);
+ GetClientRect((HWND) windowId, &r);
+ }
+ OnResize(core::dimension2d<s32>(r.right, r.bottom));
+
+ return true;
+}
//! presents the rendered scene on the screen, returns false if failed
bool COpenGLDriver::endScene( s32 windowId, core::rect<s32>* sourceRect )
@@ -764,7 +812,7 @@
CNullDriver::endScene( windowId );
#ifdef _IRR_WINDOWS_
- return SwapBuffers(HDc) == TRUE;
+ return SwapBuffers(currentHDC) == TRUE;
#endif
#ifdef LINUX
@@ -2261,7 +2309,7 @@
void COpenGLDriver::OnResize(const core::dimension2d<s32>& size)
{
CNullDriver::OnResize(size);
- glViewport(0, 0, size.Width, size.Height);
+ setViewPort(core::rect<s32>(0, 0, size.Width, size.Height));
}
diff -uBb -x .cbp Irrlicht.svn/COpenGLDriver.h Irrlicht/COpenGLDriver.h
--- Irrlicht.svn/COpenGLDriver.h Tue Mar 27 12:00:39 2007
+++ Irrlicht/COpenGLDriver.h Sat Mar 31 10:15:59 2007
@@ -46,6 +46,20 @@
#endif
#endif
+struct SGLContext
+{
+ SGLContext() {}
+ ~SGLContext() {}
+
+#ifdef _IRR_WINDOWS_
+ HDC hdc;
+ HGLRC ctx;
+ HWND hwnd;
+#endif
+ int width;
+ int height;
+};
+
namespace irr
{
namespace video
@@ -64,6 +78,9 @@
//! inits the windows specific parts of the open gl driver
bool initDriver(const core::dimension2d<s32>& screenSize, HWND window,
u32 bits, bool fullscreen, bool vsync);
+
+ //! initializes a GL context for a given window ID
+ HDC getGLContext(HWND window, u32 bits);
#endif
#ifdef LINUX
@@ -85,6 +102,8 @@
//! clears the zbuffer
virtual bool beginScene(bool backBuffer, bool zBuffer, SColor color);
+ virtual bool setRenderWindow(s32 windowId);
+
//! sets transformation
virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat);
@@ -433,10 +452,15 @@
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC pGlFramebufferRenderbufferEXT;
#endif
+ core::array<struct SGLContext> glcontext;
+ GLuint PixelFormat;
+
#ifdef _IRR_WINDOWS_
HDC HDc; // Private GDI Device Context
HWND Window;
HGLRC HRc; // Permanent Rendering Context
+ u32 bpp;
+ HDC currentHDC;
#elif defined(LINUX)
GLXDrawable XWindow;
Display* XDisplay;
Therefore i needed to do a tiny extension of the driver-API, to be used like this:
driver->setRenderWindow((s32)GetHandle());
driver->beginScene(true, true, SColor(100, 100, 100, 100));
// ...do some drawing here
driver->endScene();
It's only implemented for the win code path at the moment.
thx for commenting!
bye mrc