OGL multiple render windows patch

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
mrcdrc
Posts: 7
Joined: Sat Mar 31, 2007 10:26 am

OGL multiple render windows patch

Post by mrcdrc »

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:

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;
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
mrcdrc
Posts: 7
Joined: Sat Mar 31, 2007 10:26 am

forgot one thing

Post by mrcdrc »

you also need to add

Code: Select all

virtual bool setRenderWindow(s32 windowId = 0) = 0;

to IVideoDriver.h around line 163.

bye
mrc
Cez
Posts: 3
Joined: Wed May 21, 2008 6:42 pm

Post by Cez »

Hello,

I was wondering if there were any plan to add this functionality to Irrlicht ? Because changing Irrlicht's device WinID is only possible in DirectX.

Thanks.

And sorry to post on this old thread !
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, it's planned, but not this way. I'll simply add the window change mechanism to beginScene (also for D3D). Might already be in Irrlicht 1.5
Post Reply