Skip to main content
GameDev.net gamedev.net
🔒 Locked

Please help on my win32 opengl code

Started by Janju Jan 16, 2006 at 6:32 AM 4 replies 1k views
Original Post
Janju
Janju
As far as i can tell everything should work fine with this code, but i have some questions: 1. Is everything deinitialised right when an error ocours by calling PostMessage(hwnd,WM_CLOSE,0,0); //? I am asking this, because the debugger won't stop in the switch(msg){[...]} 2. Do i use ShowWindow(hwnd, nCmdShow); // and UpdateWindow(hwnd); // correctly? 3. Do you see any other obvious flaws?
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>

const char g_szClassName[] = "myWindowClass";

HWND		hwnd=NULL;
HINSTANCE	hInstance=NULL;
HDC			hDC=NULL;		
HGLRC		hRC=NULL;		
double		r = 0.0;

int InitGL(GLsizei width, GLsizei height)		
{
	if (height==0)		
	{
		height=1;			
	}

	glViewport(0,0,width,height);	

	glMatrixMode(GL_PROJECTION);		
	glLoadIdentity();									
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); 

	glMatrixMode(GL_MODELVIEW);							
	glLoadIdentity();

	return TRUE;										
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_CLOSE:
		if (hRC)											// Do We Have A Rendering Context?
		{
			if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
			{
				MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			}

			if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
			{
				MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			}
			hRC=NULL;										// Set RC To NULL
		}

		if (hDC && !ReleaseDC(hwnd,hDC))					// Are We Able To Release The DC
		{
			MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			hDC=NULL;										// Set DC To NULL
		}

		if (hwnd && !DestroyWindow(hwnd))					// Are We Able To Destroy The Window?
		{
			MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			hwnd=NULL;										// Set hWnd To NULL
		}

		if (!UnregisterClass("OpenGL",hInstance))			// Are We Able To Unregister Class
		{
			MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			hInstance=NULL;									// Set hInstance To NULL
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine, int nCmdShow)
{
	GLuint PixelFormat;
	WNDCLASSEX wc;

	MSG Msg;

	int width = 240, height = 160;

	hInstance = GetModuleHandle(NULL);

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = g_szClassName;
	wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

	if(!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Window Registration Failed!", "Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	hwnd = CreateWindowEx(
		WS_EX_CLIENTEDGE,
		g_szClassName,
		"The title of my window",
		WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
		CW_USEDEFAULT, CW_USEDEFAULT, width, height,
		NULL, NULL, hInstance, NULL);

	if(hwnd == NULL)
	{
		MessageBox(NULL, "Window Creation Failed!", "Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
			1,											// Version Number
			PFD_DRAW_TO_WINDOW |						// Format Must Support Window
			PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
			PFD_DOUBLEBUFFER,							// Must Support Double Buffering
			PFD_TYPE_RGBA,								// Request An RGBA Format
			16,											// Select Our Color Depth
			0, 0, 0, 0, 0, 0,							// Color Bits Ignored
			0,											// No Alpha Buffer
			0,											// Shift Bit Ignored
			0,											// No Accumulation Buffer
			0, 0, 0, 0,									// Accumulation Bits Ignored
			16,											// 16Bit Z-Buffer (Depth Buffer)  
			0,											// No Stencil Buffer
			0,											// No Auxiliary Buffer
			PFD_MAIN_PLANE,								// Main Drawing Layer
			0,											// Reserved
			0, 0, 0										// Layer Masks Ignored
	};

	if (!(hDC=GetDC(hwnd)))							// Did We Get A Device Context?
	{
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		PostMessage(hwnd,WM_CLOSE,0,0);
		return FALSE;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		PostMessage(hwnd,WM_CLOSE,0,0);
		return FALSE;								// Return FALSE
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		PostMessage(hwnd,WM_CLOSE,0,0);
		return FALSE;								// Return FALSE
	}

	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
	{
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		PostMessage(hwnd,WM_CLOSE,0,0);
		return FALSE;								// Return FALSE
	}

	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
	{		
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		PostMessage(hwnd,WM_CLOSE,0,0);
		return FALSE;								// Return FALSE
	}


	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	if (!InitGL(width,height))							// Initialize Our Newly Created GL Window
	{
		PostMessage(hwnd,WM_CLOSE,0,0);
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	int done = false;

	while(!done)
	{
		if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
		{
			if (Msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;							// If So done=TRUE
			}
			else									// If Not, Deal With Window Messages
			{
				TranslateMessage(&Msg);				// Translate The Message
				DispatchMessage(&Msg);				// Dispatch The Message
			}
		}
		else
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glLoadIdentity();								

			// 
			glRotated(r,0,0,1);
			r+=0.1;
			glBegin(GL_TRIANGLES);					
			glVertex3f( 0.0f, 1.0f, -15.0f);		
			glVertex3f(-1.0f,-1.0f, -15.0f);		
			glVertex3f( 1.0f,-1.0f, -15.0f);		
			glEnd();		

			SwapBuffers(hDC);				
		}
		

		
	}
	return Msg.wParam;
}
Skeleton_V@T
Skeleton_V@T
From my first glance, you may consider reviewing these:
  1. It is not a good idea to call DestroyWindow () and UnregisterClass () in the window procedure. There maybe remaining messages in the message queue, and there're lots of housekeeping works Windows has to perform when a window get destroyed. You should move them out of window procedure, the best place is right before WinMain () returns I guess.

  2. The default case of switch (Msg) statement is probably better not to process DefWindowProc (). I generally prefer writing the window procedure like this:
    LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam){    switch (Msg)    {    case WM_CLOSE:        PostQuitMessage (0) ; //No error        return 0 ;    }    //Process nothing        return DefWindowProc (hWnd, Msg, wParam, lParam) ;}

    This way the function doesn't have an extra jump (break) statement, which might improve performance.

  3. hInstance = GetModuleHandle(NULL);
    You may get the instance through hInstance parameter of the main function instead. And consider changing the global variable name to g_hInstance or some sort of it. HDC and HGLRC should be considered also.

  4. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    You don't really need to provide the background for your window here as you'll probably redraw the entire window's client area by OpenGL drawing routines anyway. This might improve performance.

  5. WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX
    You may archive the same thing with WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX values. The window style should have these values also: WS_CLIPCHILDREN | WS_CLIPSIBLINGS, for explanation you can take a look at MSDN - PIXELFORMATDESCRIPTOR.

  6. You don't need to call ShowWindow () and UpdateWindow (), you may add WS_VISIBLE to the window style to make it visible when created. The UpdateWindow () causes the system to send a WM_PAINT message to your window, but you probably don't process WM_PAINT here but through your own drawing loop instead.

  7. You've got InitGL (), so it is probably better to separate your window creation routine with the WinMain () function by a new function. CreateGLWindow () for example. It is better to have a class though.

  8. The Msg variable should be moved to be in front of the while loop (or in the loop itself), you don't need it until later.


I believe there're some more [wink], but it's probably enough for now. You may encapsulate all the OpenGL creating/destroying routines to a class later for better maintenance.
--> The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones <--
Dim_Yimma_H
Dim_Yimma_H
I think Skeleton_V@T covered most of it, but I noticed that the calls to PostMessage when error checking might not handle WM_CLOSE.

PostMessage posts a message to the queue, but does not immediately process the message. So if you call PostMessage(hwnd, WM_CLOSE, 0, 0) and then return FALSE the WM_CLOSE won't be handled. Usually WndProc would be entered and WM_CLOSE handled when calling DispatchMessage(&Msg) in your message loop, because the WM_CLOSE message is retrieved from the queue using PeekMessage.

Details here: PostMessage

To make sure the WM_CLOSE message is handled you can call SendMessage(hwnd, WM_CLOSE, 0, 0) instead, see details here: SendMessage
That way your release and DestroyWindow(hwnd) calls would be made when handling the WM_CLOSE message.
Janju
Janju
Quote:
1. It is not a good idea to call DestroyWindow () and UnregisterClass () in the window procedure. There maybe remaining messages in the message queue, and there're lots of housekeeping works Windows has to perform when a window get destroyed. You should move them out of window procedure, the best place is right before WinMain () returns I guess.
That doesn't seem to work either. I get error messages that the programm failed to release stuff.

Quote:
2. This way the function doesn't have an extra jump (break) statement, which might improve performance.
Dunno if that's right. Ok changed.

Quote:
3.
Makes sense. :)

Quote:
4.
So i have to set it to = NULL; right?

Quote:
5.
But is this change really neccesary? I don't find anything about WS_CLIPCHILDREN | WS_CLIPSIBLINGS being neccesary:
Quote:
WS_CLIPSIBLINGS Clips child windows relative to each other; that is, when a particular child window receives a paint message, the WS_CLIPSIBLINGS style clips all other overlapped child windows out of the region of the child window to be updated. (If WS_CLIPSIBLINGS is not given and child windows overlap, when you draw within the client area of a child window, it is possible to draw within the client area of a neighboring child window.) For use with the WS_CHILD style only.


Quote:
6.
AH ok, thanks. Anyways if i remove ShowWindow and use WS_VISIBLE the start up of the window looks weird.

Quote:
7.
Ok.

Quote:
8.
I think it's a good style to put variables down at the beginning of a procedure

Here the code again:
#include <windows.h>#include <gl\gl.h>#include <gl\glu.h>const char g_myClassName[] = "myWindowClass";HWND		hwnd=NULL;HINSTANCE	g_hInstance=NULL;HDC			g_hDC=NULL;		HGLRC		g_hRC=NULL;		double		r = 0.0;int InitGL(GLsizei width, GLsizei height)		{	if (height==0)			{		height=1;				}	glViewport(0,0,width,height);		glMatrixMode(GL_PROJECTION);			glLoadIdentity();										gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); 	glMatrixMode(GL_MODELVIEW);								glLoadIdentity();	return TRUE;										}int DeinitWindow(){	if (g_hRC)											// Do We Have A Rendering Context?	{		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?		{			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);		}		if (!wglDeleteContext(g_hRC))						// Are We Able To Delete The RC?		{			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);		}		g_hRC=NULL;										// Set RC To NULL	}	if (g_hDC && !ReleaseDC(hwnd,g_hDC))					// Are We Able To Release The DC	{		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);		g_hDC=NULL;										// Set DC To NULL	}	if (hwnd && !DestroyWindow(hwnd))					// Are We Able To Destroy The Window?	{		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);		hwnd=NULL;										// Set hWnd To NULL	}	if (!UnregisterClass("OpenGL",g_hInstance))			// Are We Able To Unregister Class	{		MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);		g_hInstance=NULL;									// Set hInstance To NULL	}	return 0;}LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){	switch(msg)	{	case WM_CLOSE:		DeinitWindow();				break;	case WM_DESTROY:		PostQuitMessage(0);		break;	}	return DefWindowProc(hwnd, msg, wParam, lParam);}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,				   LPSTR lpCmdLine, int nCmdShow){	unsigned int PixelFormat;	WNDCLASSEX wc;	int width = 240, height = 160;	int done = false;	g_hInstance = hInstance;	wc.cbSize        = sizeof(WNDCLASSEX);	wc.style         = 0;	wc.lpfnWndProc   = WndProc;	wc.cbClsExtra    = 0;	wc.cbWndExtra    = 0;	wc.hInstance     = hInstance;	wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);	wc.hbrBackground = NULL;	wc.lpszMenuName  = NULL;	wc.lpszClassName = g_myClassName;	wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);	if(!RegisterClassEx(&wc))	{		MessageBox(NULL, "Window Registration Failed!", "Error!",			MB_ICONEXCLAMATION | MB_OK);		return 0;	}	hwnd = CreateWindowEx(		WS_EX_CLIENTEDGE,		g_myClassName,		"Der Titel des Fensters",		WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,		CW_USEDEFAULT, CW_USEDEFAULT, width, height,		NULL, NULL, hInstance, NULL);	if(hwnd == NULL)	{		MessageBox(NULL, "Window Creation Failed!", "Error!",			MB_ICONEXCLAMATION | MB_OK);		return 0;	}	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be	{		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor			1,											// Version Number			PFD_DRAW_TO_WINDOW |						// Format Must Support Window			PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL			PFD_DOUBLEBUFFER,							// Must Support Double Buffering			PFD_TYPE_RGBA,								// Request An RGBA Format			16,											// Select Our Color Depth			0, 0, 0, 0, 0, 0,							// Color Bits Ignored			0,											// No Alpha Buffer			0,											// Shift Bit Ignored			0,											// No Accumulation Buffer			0, 0, 0, 0,									// Accumulation Bits Ignored			16,											// 16Bit Z-Buffer (Depth Buffer)  			0,											// No Stencil Buffer			0,											// No Auxiliary Buffer			PFD_MAIN_PLANE,								// Main Drawing Layer			0,											// Reserved			0, 0, 0										// Layer Masks Ignored	};	if (!(g_hDC=GetDC(hwnd)))							// Did We Get A Device Context?	{		DeinitWindow();		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);		return FALSE;								// Return FALSE	}	if (!(PixelFormat=ChoosePixelFormat(g_hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?	{		DeinitWindow();		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);		return FALSE;								// Return FALSE	}	if(!SetPixelFormat(g_hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?	{		DeinitWindow();		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);		return FALSE;								// Return FALSE	}	if (!(g_hRC=wglCreateContext(g_hDC)))				// Are We Able To Get A Rendering Context?	{		DeinitWindow();		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);		return FALSE;								// Return FALSE	}	if(!wglMakeCurrent(g_hDC,g_hRC))					// Try To Activate The Rendering Context	{				DeinitWindow();		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);		return FALSE;								// Return FALSE	}	ShowWindow(hwnd, nCmdShow);	if (!InitGL(width,height))							// Initialize Our Newly Created GL Window	{				DeinitWindow();		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);				return FALSE;								// Return FALSE	}	MSG Msg;	while(!done)	{		if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?		{			if (Msg.message==WM_QUIT)				// Have We Received A Quit Message?			{				done=TRUE;							// If So done=TRUE			}			else									// If Not, Deal With Window Messages			{				TranslateMessage(&Msg);				// Translate The Message				DispatchMessage(&Msg);				// Dispatch The Message			}		}		else		{			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			glLoadIdentity();											// 			glRotated(r,0,0,1);			r+=0.1;			glBegin(GL_TRIANGLES);								glVertex3f( 0.0f, 1.15470f, -10.0f);					glVertex3f(-1.0f,-0.57735f, -10.0f);					glVertex3f( 1.0f,-0.57735f, -10.0f);					glEnd();					SwapBuffers(g_hDC);						}	}	return (int)Msg.wParam;}
Skeleton_V@T
Skeleton_V@T
I've just tried your code, it ran fine, there's a small white 2D triangle rotating in the middle of the black client area. It showed me no error messages when exited.

Quote:
I think it's a good style to put variables down at the beginning of a procedure

This is the C coding style, neither it is efficient nor pretty looking. The program has to preallocate some memory but far later it is used (or if there's an error, it never has a chance to be utilized). You will probably have to look it up several times when writing code also.

Quote:
But is this change really neccesary? I don't find anything about WS_CLIPCHILDREN | WS_CLIPSIBLINGS being neccesary

I don't include it in my code either, but I've got a note there in case I want to embed some of the Win32 controls to my window.
Quote:
SetPixelFormat ()
An OpenGL window has its own pixel format. Because of this, only device contexts retrieved for the client area of an OpenGL window are allowed to draw into the window. As a result, an OpenGL window should be created with the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles. Additionally, the window class attribute should not include the CS_PARENTDC style.


Quote:
So i have to set it to = NULL; right?

Yes.
--> The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones <--
Janju
Janju
Thanks Skeleton_V@T you are a big help.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.