Initializing OpenGL in Windows 7 - WITHOUT GLUT

First, I’d like to apologize if this question has been addressed before, or if there is a more suitable place in these forums for it.

I’m building a platform-independent game engine, which will include an OpenGL rendering module. I’m using GLEW for the boilerplate code regarding the GL API. An important note, I’m not using nor do I wish to use GLUT (it’s sometimes annoying following tutorials as almost all of them are plagued with using GLUT)… I will be doing the platform-dependent window code myself (for greater control).

I’m currently testing this code on a computer with 1x GeForce 8800GTX, and I’m quite sure version 2 of OpenGL is supported (OpenGL Extension Viewer said this hardware supports version 3). I’m using VS2010 Ultimate, my CPU is a Core 2 Duo E6850, Win 7 x64 but I’m compiling a 32-bit version only.

I’m having a problem, currently on Windows 7: I am able to create a window, but OpenGL initialization is failing on wglCreateContextAttribsARB with GetLastError() returning 3221692565.

This is the initialization code I have so far (based on several tutorials I saw online):

bool GLGraphicsEngine::Init()
	{
	//	OutputDebugString(L"GL Init called
");
		// now that we have a window, setup the pixel format descriptor
		m_glHDC = GetDC(m_hWnd);
		int height, width, x, y;
		x = m_MainWindow->GetClientX();
		y = m_MainWindow->GetClientY();
		height = m_MainWindow->GetClientHeight();
		width = m_MainWindow->GetClientWidth();

		std::wstringstream ws;
		ws << "X: " << x << "	Y: " << y << "	Height: " << height << "	Width: " << width << std::endl;
		OutputDebugString(ws.str().c_str());


		// Set a dummy pixel format so that we can get access to wgl functions
		PIXELFORMATDESCRIPTOR pfd;
		ZeroMemory(&pfd, sizeof(pfd));
		GLint iPixelFormat = 1;

		if(!SetPixelFormat(m_glHDC, iPixelFormat, &pfd/*&m_glpfd*/))
		{
			OutputDebugString(L"SetPixelFormatFailed");
			return false;
		}

		// Create OGL context and make it current
		m_glRC = wglCreateContext( m_glHDC );
		wglMakeCurrent( m_glHDC, m_glRC );
		if (m_glHDC == 0 || m_glRC == 0)
		{
			OutputDebugString(L"An error occured creating an OpenGL window.
");
			return false;
		}

		// Setup GLEW which loads OGL function pointers
		GLenum err = glewInit();
		if(GLEW_OK != err)
		{
			/* Problem: glewInit failed, something is seriously wrong. */
			std::cerr << "GLEW Init Error: " << glewGetErrorString(err) << std::endl;
			return false;
		}
		m_oglVersion = glGetString(GL_VERSION);

#ifdef _DEBUG
		DebugPrintVersion();
#endif
		// Now that extensions are setup,
		// delete window and start over picking a real format.
		wglMakeCurrent(NULL, NULL);
		wglDeleteContext(m_glRC);
		ReleaseDC(m_hWnd, m_glHDC);
		DestroyWindow(m_hWnd);

		// Create the window again
		m_hWnd = m_MainWindow->InitWindow();
		m_glHDC = GetDC(m_hWnd);

		int nPixCount =0;
		int nPixelFormat;
		// Specify the important attributes we care about
		int pixAttribs[] =
		{
			WGL_SUPPORT_OPENGL_ARB, 1, // Must support OGL rendering
			WGL_DRAW_TO_WINDOW_ARB, 1, // pf that can run a window
			WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, // must be HW accelerated
			WGL_COLOR_BITS_ARB, 24, // 8 bits of each R, G and B
			WGL_DEPTH_BITS_ARB, 16, // 16 bits of depth precision for window
			WGL_DOUBLE_BUFFER_ARB, GL_TRUE, // Double buffered context
			WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, // MSAA on
			WGL_SAMPLES_ARB, 8, // 8x MSAA
			WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, // pf should be RGBA type
			0 // NULL termination
		}; 
		// Ask OpenGL to find the most relevant format matching our attribs
		// Only get one format back.
		BOOL lolRet = wglChoosePixelFormatARB(m_glHDC, pixAttribs, NULL, 1, &nPixelFormat, (UINT*)&nPixCount);

		if(nPixelFormat != -1)
		{
			if (!lolRet)
				OutputDebugString(L"wglChoosePixelFormatARB returns FALSE
");
			if (nPixelFormat == 0)
				OutputDebugString(L"nPixelFormat is 0!
");
			// Got a format, now set it as the current one
			SetPixelFormat(m_glHDC, nPixelFormat, &m_glpfd);
			
			int attribs[] =
			{
				WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
				WGL_CONTEXT_MINOR_VERSION_ARB, 2,
				WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
				0
			};

			OutputDebugString(L"Pre ARB checking...
");

			if(wglewIsSupported("WGL_ARB_create_context") == 1)
				OutputDebugString(L"wglCreateContextAttribsARB supported!
");
			else
				OutputDebugString(L"wglCreateContextAttribsARB not supported!
");

		//	m_glRC = wglCreateContext( m_glHDC );//wglCreateContextAttribsARB(m_glHDC, 0, NULL);
			m_glRC = wglCreateContextAttribsARB(m_glHDC, 0, attribs);
			if (m_glRC == NULL)
			{
				// Handle Error . . .
				DWORD err = GetLastError();
				std::wstringstream ws3;
				ws3 << "Rendering context is null: " << err << std::endl;
				OutputDebugString(ws3.str().c_str());
			}
			wglMakeCurrent( m_glHDC, m_glRC );
		}
		ShowWindow( m_hWnd, SW_SHOW );
		SetForegroundWindow( m_hWnd );
		SetFocus( m_hWnd );

		return true;
	}

(m_MainWindow points to an instance of a class I made, which encapsulates the concept of a window)

I’m literally pulling my hair, as I’ve looked for information everywhere, but can’t seem to solve this. Since the initialization of OpenGL is failing (on the function I mentioned), the render function I’m using is not producing anything and I get a window with its contents set to white.

I also provide the rendering code if anyone’s interested:

void GLGraphicsEngine::Render()
	{
		// 1. set up the viewport
		int x = m_MainWindow->GetClientX();
		int y = m_MainWindow->GetClientY();
		int height = m_MainWindow->GetClientHeight();
		int width = m_MainWindow->GetClientWidth(); 

		
		glViewport(x, y, width, height);
		// set viewport
		// to be the whole width and height
		// of the CLIENT AREA (drawable region) of the window,
		// (the CLIENT AREA excludes the titlebar and the
		// maximize/minimize buttons).

		
		// 2. projection matrix
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(45.0,(float)width/(float)height, 1, 1000);

		// 3. viewing transformation
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		gluLookAt(  0, 0, 10,
					0, 0, 0,
					0, 1, 0);

		// 4. modelling transformation and drawing
		glClearColor( 0.5, 0, 0, 0 );
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		static float i = 0.01f;

		i+= 0.001f;     // increase i by 0.001 from its
		// it had on the LAST FUNCTION CALL to the draw() function
/*		std::wstringstream ws;
		ws << "GLVersion: " << *m_oglVersion << "	height: " << height <<"	width: " << width << "	i: " << i << std::endl;
		OutputDebugString(ws.str().c_str()); */
		


		float c = cos( i );
		float s = sin( i );

		glBegin (GL_TRIANGLES);
			glColor3f(  c, 0, 0 );      // red
			glVertex3f( 1+c, 0+s, 0 );

			glColor3f(  c, s, 0 );      // yellow
			glVertex3f( 0+c, 1+s, 0 );

			glColor3f(  s, 0.1f, s );   // magenta
			glVertex3f(-1+c, 0+s, 0 );
		glEnd(); 

		//7.  SWAP BUFFERS.
		SwapBuffers(m_glHDC);
		// Its important to realize that the backbuffer
		// is intelligently managed by the HDC ON ITS OWN,
		// so all's you gots to do is call SwapBuffers
		// on the HDC of your window.
	}

wglCreateContext and wglCreateContextAttribsARB use your initial context, which doesnt exist anymore because you got rid of it!
You cant call wglMakeCurrent(NULL, NULL); until AFTER you have finished creating the new context for the second window.
The section of code:

		wglMakeCurrent(NULL, NULL);
		wglDeleteContext(m_glRC);
		ReleaseDC(m_hWnd, m_glHDC);
		DestroyWindow(m_hWnd);

needs to be moved to after the wglCreateContext, wglCreateContextAttribsARB calls, and you need separate DC, hWnd & RC variables for the two windows.

An important note, I’m not using nor do I wish to use GLUT (it’s sometimes annoying following tutorials as almost all of them are plagued with using GLUT)… I will be doing the platform-dependent window code myself (for greater control).

How exactly is GLUT a “plague”? If you’re teaching someone OpenGL, you don’t need to clutter the lessons with pointless stuff about rendering contexts, platform-specific windowing APIs, and other nonsense. A good teaching aid is defined most by what it doesn’t teach, not what it does.

Anyway, GLUT is far from the only platform independent means of creating OpenGL windows. There are GLFW, SDL, and SMFL, all of which provide plenty of control. What is it that you are trying to do that requires that you not use any of them?

I’m having a problem, currently on Windows 7: I am able to create a window, but OpenGL initialization is failing on wglCreateContextAttribsARB with GetLastError() returning 3221692565.

You called glewInit, but does glewInit initialize WGL functions as well? I seem to recall there being a specific wglewInit for those.

wglCreateContext and wglCreateContextAttribsARB use your initial context, which doesnt exist anymore because you got rid of it!

No, they don’t. WGL functions are not dependent on a rendering context. You need the RC to get them, but you can call them just fine after destroying that RC. And no rendering context has to be current to call them. I have some code that seems to be working just fine that does exactly that.


WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,

Maybe the driver doesn’t know how to be compatible to that OpenGL version.

And try 24 bits depth anyway.
One could argue about 32 bits of color bits RGBA being better aligned.

Alfonse Reinheart: perhaps I didn’t explain myself clearly… I was not only looking for tutorials on OpenGL, but more specifically, tutorials that do not make use of GLUT or other libraries (though I might give SDL a chance). In that way, I called GLUT a “plague” :P! And glewInit() does initialize the windows functionality (http://glew.sourceforge.net/basic.html).

mbentrup: I’m using OpenGL Extensions Viewer 4.02 and it says it supports up to 3.3, so I’m pretty sure that is not the issue.

ZbuffeR: tried that, no change.

Lets look into the spec:

The defined versions of OpenGL at the time of writing are OpenGL
1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 2.1, 3.0, 3.1, and 3.2. Feature
deprecation was introduced with OpenGL 3.0, so forward-compatible
contexts may only be requested for OpenGL 3.0 and above. Thus,
examples of invalid combinations of attributes include:

  - Major version &lt; 1 or &gt; 3
  - Major version == 1 and minor version &lt; 0 or &gt; 5
  - [b]Major version == 2 and minor version &lt; 0 or &gt; 1[/b]
  - Major version == 3 and minor version &gt; 2
  - [b]Forward-compatible flag set and major version &lt; 3[/b]

No, your driver should not be able to create an OpenGL 2.2 context, especially not if you request a forward-compatible context.

GLUT is a good cross-platform library for teaching openGL and simple quick demos. It is definitely not the plague. Freeglut even has extensions for simply setting up forward compatible openGL contexts (as does SDL) without having to deal with OS specifics.


void glutInitContextVersion( int majorVersion, int minorVersion );
void glutInitContextFlags( int flags );
void glutInitContextProfile( int profile );

Some alternative CROSS-PLATFORM libraries to GLUT that you might also benefit from trying in addition to SDL …

simple and fast multimedia libray

glfw

mbentrup: the prize goes to you! Can’t believe how I missed that info… It is working now!

marshats: I wasn’t stating it’s worthless, but merely that I didn’t want to use it. Out of curiosity, would I be able to have fine-grained control over the main loop in GLUT? (Since GLUT has its own from what I’ve seen) Would I have to feed callback functions to GLUT, which would then be called on specific parts of the GLUT loop iteration? (something simmilar to DXUT with D3D) I will also take a look at your suggestions.

Thanks for the help people!

I was not only looking for tutorials on OpenGL, but more specifically, tutorials that do not make use of GLUT or other libraries (though I might give SDL a chance).

You didn’t answer my question: why does it matter so much to you that you manually write platform-specific code to create and manage OpenGL windows? Do you have an actual need? Or is it just that all too common belief among neophyte programmers that doing everything themselves is better than using someone else’s perfectly functional and well-debugged code?

It may not seem like a good reason, but I wanted to see the code necessary for managing windows in the different systems myself (learning purpose, in a certain way). Never know when it will be useful to have knowledge/experience about something in particular…

I confess I didn’t put in enough research into what is already mature and widely used. Regarding your comment about neophyte programmers (kind of harsh): while I prefer to use code I made, I’m not exactly a blind zealot that will reinvent the wheel whenever a specific need arises. Otherwhise I would not be using libs such as Boost, for example. I guess it’s more of an automatic voice in my head saying “it probably has license fees” whenever I think about third party code. Again, not enough research from my side I guess.

freeglut seems well accepted these days over the original glut … it adds some openGL context creation and finer grained control of the mainloop. For instance, see example glutMainLoopEvent in action. It still relies on callbacks but allows the user to control the main control loop rather than the old way of glut (as opposed to freeglut) taking total control of the loop. If you don’t like callbacks then the other libraries that were mentioned in a previous post may be more to your liking.