Sign in to follow this  
xyuri

Basic GameLoop Issues using Windows Messaging ...

Recommended Posts

I have never created an actual game loop using a window that I have created myself and implimenting messages and whatnot ... but what I thought would simply work doesnt work. Could someone help me out a bit? This is the main hassle bit:
	do
	{
	    while(GetMessage(&msg, hWnd, 0, 0)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
	    }
		XPos = 5.0;
		//Frame?
	} while (GameRuns == 1);
The XPos = 5.0 bit is never reached :-( Why is this? If you want a look at ALL of the code then here it is:
#include <windows.h>			/* must include this before GL/gl.h */
#include <GL/gl.h>			/* OpenGL header file */
#include <GL/glu.h>			/* OpenGL utilities header file */
//#include <stdio.h>

int GameRuns = 1;

GLfloat XPos = 0.0;

//int FORM_WIDTH, FORM_HEIGHT;

void display()
{

	// MODELVIEW TRANSFORMATION
	//glMatrixMode(GL_MODELVIEW);
	//clearing the background with the color specified
	glClearColor(0.0f,1.0f,0.0f,1.0f);
	//glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	//glMatrixMode(GL_PROJECTION);
	//glLoadIdentity();
	//gluPerspective(50.0, 1.0, 3.0, 7.0);
	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();
	//glTranslatef(-0.5f,0.0f,-0.0f);
	// Finished Drawing The Triangle
	//gluPerspective(50.0, 1.0, 1.0, 100.0);
	//gluLookAt(-1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	/* PUSHING THE MATRIX STACK */
	//glPushMatrix();
	/*glLoadIdentity();
	glTranslatef(0.0, 0.0, -0.56);
	glBegin(GL_TRIANGLES);						// Drawing Using Triangles
		glColor3f(0.0f, 0.0f, 1.0f);			// Blue Colour
		glVertex3f( 0.0f, 1.0f, -1.0f);			// Top
		glVertex3f(-1.0f,-1.0f, -1.0f);			// Bottom Left
		glVertex3f( 1.0f,-1.0f, -1.0f);			// Bottom Right
	glEnd();*/
	//glPopMatrix();

	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
        gluPerspective(50.0, 1.0, 1.0, 100.0);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
    gluLookAt(-0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	
	/*glBegin(GL_TRIANGLES);						// Drawing Using Triangles
		glColor3f(0.0f, 0.0f, 1.0f);
		glVertex3f( 0.0f, 1.0f, -1.0f);				// Top
		glVertex3f(-1.0f,-1.0f, -1.0f);				// Bottom Left
		glVertex3f( 1.0f,-1.0f, -1.0f);				// Bottom Right
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex3f( 0.0f, 1.0f, -2.0f);				// Top
		glVertex3f(-1.0f,-1.0f, -2.0f);				// Bottom Left
		glVertex3f( 1.0f,-1.0f, -2.0f);				// Bottom Right
	glEnd();							// Finished Drawing The Triangle*/

	glBegin(GL_TRIANGLES);						// Drawing Using Triangles
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex3f( -9.5f + XPos, 1.0f, -2.0f);				// Top
		glVertex3f(-10.0f + XPos,-1.0f, -2.0f);				// Bottom Left
		glVertex3f( -9.0f + XPos,-1.0f, -2.0f);				// Bottom Right
	glEnd();							// Finished Drawing The Triangle

    glFlush();
}


LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ 
    static PAINTSTRUCT ps;

	switch(uMsg) 
	{
		case WM_PAINT:
			display();
			BeginPaint(hWnd, &ps);
			EndPaint(hWnd, &ps);
			return 0;
		case WM_SIZE:
			/*FORM_WIDTH = LOWORD(lParam);
			FORM_HEIGHT = HIWORD(lParam);*/
			glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));

		  	// PROJECTION TRANSFORMATION
		  	//glMatrixMode(GL_PROJECTION);
		  	//glLoadIdentity();
		  	//glFrustum(10, 10, 10, 10, 1, 20);

			PostMessage(hWnd, WM_PAINT, 0, 0);
			return 0;
		case WM_CHAR:
			/* WHEN EXCAPE KEY IS PRESSED */
			switch (wParam) 
			{
				case 27:			/* ESC key */
				GameRuns = 0;
				PostQuitMessage(0);
				break;
			}
			return 0;
		case WM_CLOSE:
			/* WHEN THE WINDOW IS CLOSED BY PRESSING X BUTTON */
			GameRuns = 0;
			PostQuitMessage(0);
			return 0;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 

HWND CreateOpenGLWindow(char* title, int x, int y, int width, int height, BYTE type, DWORD flags)
{
    int         pf;
    HDC         hDC;
    HWND        hWnd;
    WNDCLASS    wc;
    PIXELFORMATDESCRIPTOR pfd;
    static HINSTANCE hInstance = 0;

    /* only register the window class once - use hInstance as a flag. */
    if (!hInstance) 
	{
		hInstance = GetModuleHandle(NULL);
		wc.style         = CS_OWNDC;
		wc.lpfnWndProc   = (WNDPROC)WindowProc;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = hInstance;
		wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
		wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = NULL;
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = "OpenGL";
		if (!RegisterClass(&wc)) 
		{
		    MessageBox(NULL, "RegisterClass() failed:  Cannot register window class.", "Error", MB_OK);
		    return NULL;
		}
    }

    hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, x, y, width, height, NULL, NULL, hInstance, NULL);

    if (hWnd == NULL) 
	{
		MessageBox(NULL, "CreateWindow() failed:  Cannot create a window.", "Error", MB_OK);
		return NULL;
    }

    hDC = GetDC(hWnd);

    /* there is no guarantee that the contents of the stack that become
       the pfd are zeroed, therefore _make sure_ to clear these bits. */
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize        = sizeof(pfd);
    pfd.nVersion     = 1;
    pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
    pfd.iPixelType   = type;
    pfd.cColorBits   = 32;

    pf = ChoosePixelFormat(hDC, &pfd);
    if (pf == 0) 
	{
		MessageBox(NULL, "ChoosePixelFormat() failed:  Cannot find a suitable pixel format.", "Error", MB_OK); 
		return 0;
    } 

    if (SetPixelFormat(hDC, pf, &pfd) == FALSE) 
	{
		MessageBox(NULL, "SetPixelFormat() failed:  Cannot set format specified.", "Error", MB_OK);
		return 0;
    } 

    DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    ReleaseDC(hWnd, hDC);

    return hWnd;
}    

int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpszCmdLine, int nCmdShow)
{
    HDC hDC;				/* device context */
    HGLRC hRC;				/* opengl context */
    HWND  hWnd;				/* window */
    MSG   msg;				/* message */

    hWnd = CreateOpenGLWindow("XyuRi", 100, 100, 640, 480, PFD_TYPE_RGBA, 0);
    if (hWnd == NULL) {exit(1);}

    hDC = GetDC(hWnd);
    hRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, hRC);

    ShowWindow(hWnd, nCmdShow);

	/* ENABLE DEPTH BUFFERING! */
	glEnable(GL_DEPTH_TEST);

	do
	{
	    while(GetMessage(&msg, hWnd, 0, 0)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
	    }
		XPos = 5.0;
		//Frame?
	} while (GameRuns == 1);

    wglMakeCurrent(NULL, NULL);
    ReleaseDC(hWnd, hDC);
    wglDeleteContext(hRC);
    DestroyWindow(hWnd);

    return msg.wParam;
}


Any help with this is greatly appreciated as per usual :-)

Thanks.


Share this post


Link to post
Share on other sites
It never gets to the XPos = 5.0 as GetMessage is a blocking function, that is it does not return until after it has handled a message, which means that the loop condition is never false.

instead use PeekMessage this will allow your program to continue.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dragoncar
It never gets to the XPos = 5.0 as GetMessage is a blocking function, that is it does not return until after it has handled a message, which means that the loop condition is never false.

instead use PeekMessage this will allow your program to continue.

Thank you very much Dragoncar :-)

This document looks useful.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dragoncar
It never gets to the XPos = 5.0 as GetMessage is a blocking function, that is it does not return until after it has handled a message, which means that the loop condition is never false.

instead use PeekMessage this will allow your program to continue.

PeekMessage() is the right thing to use, but it is not entirely true that the loop condition is never false -- GetMessage() returns false when the quit message is posted. Thus, used correctly GetMessage() ensures that your program stays in the message loop as long as the main program is running. Then, when you exit, it exits the loop to allow any clean up code after the loop to run.

Share this post


Link to post
Share on other sites
Quote:
Original post by xyuri
Then what do I do with the ...
wc.lpfnWndProc   = (WNDPROC)WindowProc;

... part of my app?


The same as what you were doing before when you had the GetMessage function.

ie. This method still handles the messages recieved by your program.

Share this post


Link to post
Share on other sites
hehe, I sorta got it working ......

Because my app only draws to the screen with the PAIN message, I just told it to paint every time, therefore processing it and passing that loop ....

	do
{
//while(GetMessage(&msg, hWnd, 0, 0))

XPos += 0.001;

PostMessage(hWnd, WM_PAINT, 0, 0);

while(PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//Frame?
} while (GameRuns == 1);

Dunno if it is the correct way to go about this, but it works ... Now for double buffering to get rid of the clicker :( ....

Share this post


Link to post
Share on other sites
Well, my current game loop looks like this...


while(1)
{

if(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{

if(msg.message == WM_QUIT) break;

TranslateMessage(&msg);
DispatchMessage(&msg);

}
else
{

Update();

}

}



..and it works very well. No-one uses WM_PAINT for an app that continuously draws to it's window, such as a game. I just call ValidateRect(hWnd, NULL) in the WindowProc when a WM_PAINT message arrives, so that Windows doesn't send any more WM_PAINT messages. All my game code, including the rendering code, is called in the Update function. It's the best way to do it...

PS. You could replace the 1 in the while loop with your GameRuns variable for another way to end the program. I just use 1 and call PostQuitMessage when I want to quit the program.

Share this post


Link to post
Share on other sites
You know how every programmer has those REALLY bad days where they tear their hair out and say naughty words? Well, I'm having the opposite :-) (Wich deserves me a coffee :-))

Update() is the function where you do all the drawing with OGL ?

So, if your app has windows messages to process in the queue then it does them, otherwise it draws the next frame and repeats. I see clear now :)

Thanks a lot dude.

Share this post


Link to post
Share on other sites
Quote:
Original post by mumpo
...but it is not entirely true that the loop condition is never false -- GetMessage() returns false when the quit message is posted. Thus, used correctly GetMessage() ensures that your program stays in the message loop as long as the main program is running. Then, when you exit, it exits the loop to allow any clean up code after the loop to run.
Actually, to be pedantic, GetMessage is a tri-value API. It returns 0 when the message queue is to be terminated, but it returns values greater than zero for valid messages and values less than zero for errors. Most code ignores the fact that GetMessage returns error codes.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this