Advertisement

Getting debug information using TextOut()

Started by August 30, 2016 03:15 AM
10 comments, last by kseh 8 years, 3 months ago

Hey all,

I am trying to get some debug information using Microsoft inbuilt text display e.g. TextOut(). I am trying to make a very simple base game engine (for learning purposes) and before adding its graphics class I want to test a game state system and some other things.

My game uses this demo to get the win32 window up

https://msdn.microsoft.com/en-us/library/windows/desktop/ff381409(v=vs.85).aspx

and after ShowWindow(hwnd, nCmdShow);, I create my game Game myGame; and then call its init() function myGame.init().

In the message loop I peek messages and if no messages are to be dispatched I run game.run().

This is where I get confused: I want to write out to the things like e.g. the current game state (I am trying for a 1 second splash screen, then main menu). I can see it is working when I debug and look at my m_state variable, but I want to see it change in real time on the window, so I thought i could use TextOut. The problem is I seem to need all of the information from WM_PAINT to use textout (like the PAINTSTRUCT), but my game does not hit WM_PAINT...

Am I going about this the right way?

Thanks for all your help

You can use OutputDebugString() which will print to your console window in the debugger if you are using Visual Studio or you can see this by using DebugView without a debugger.

When dealing with GDI as TextOut is you need a WM_PAINT or similar message to update the screen in.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Advertisement

It's been quite awhile since I've written a Win32 game but if I'm not mistaken, calling InvalidateRect() causes a WM_Paint messages to be sent. Setup a timer to periodically call InvalidateRect() and you should see your text output update. You'll probably want to store that hwnd value from when you create the window so that you'll have access to it for the first parameter. You can use a NULL for the rect parameter to paint the entire window's contents and then it's just whether you want to erase the current contents of the window or not.

You can use OutputDebugString() which will print to your console window in the debugger if you are using Visual Studio or you can see this by using DebugView without a debugger.

When dealing with GDI as TextOut is you need a WM_PAINT or similar message to update the screen in.

Hi, thanks for your response. I am a bit confused first of all. I don't seem to have a 'console' window, just the win32 window that the demo creates, so I dont know where this output goes? I will have a look into DebugView.

It's been quite awhile since I've written a Win32 game but if I'm not mistaken, calling InvalidateRect() causes a WM_Paint messages to be sent. Setup a timer to periodically call InvalidateRect() and you should see your text output update. You'll probably want to store that hwnd value from when you create the window so that you'll have access to it for the first parameter. You can use a NULL for the rect parameter to paint the entire window's contents and then it's just whether you want to erase the current contents of the window or not.

Thank you, I have kind of got it to work. I am seeing the debug text flicker on the screen, as if it is getting overwritten with a blank white fill or something... I am not sure why. Win32 stuff is so confusing...

My message loop now looks like this

while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
game.run(hwnd);
InvalidateRect(hwnd, NULL, false);
}
}

with WM paint

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

//Textout output
wchar_t text[] = L"tess test test";

TextOut(hdc, 1, 1, text, ARRAYSIZE(text));
//Textout output end

//FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

EndPaint(hwnd, &ps);
}

When FillRect is not commented out the screen stays white. Thanks for all your help guys.

What value are you returning after handling WM_PAINT? It should be zero; do not pass it on to DefWindowProc, if you draw things yourself.

The flickering could well be WM_ERASEBKGND. If you do all your drawing in WM_PAINT, you can handle WM_ERASEBKGND doing nothing and return a non zero value.


Remember: The return value of a handled message is important. And, if not told otherwise in the messages docs, pass the message on to DefWindowProc. A good WindowProc looks like this:


switch ( MessageType )
{
  case WM_xxx:
    // do stuff
    return or break, depending on what the message docs say
  case WM_other_xxx:
    // do other stuff
    return or break, depending on what the message docs say
}
return DefWindowProc( arguments );

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

What value are you returning after handling WM_PAINT? It should be zero; do not pass it on to DefWindowProc, if you draw things yourself.

The flickering could well be WM_ERASEBKGND. If you do all your drawing in WM_PAINT, you can handle WM_ERASEBKGND doing nothing and return a non zero value.


Remember: The return value of a handled message is important. And, if not told otherwise in the messages docs, pass the message on to DefWindowProc. A good WindowProc looks like this:


switch ( MessageType )
{
  case WM_xxx:
    // do stuff
    return or break, depending on what the message docs say
  case WM_other_xxx:
    // do other stuff
    return or break, depending on what the message docs say
}
return DefWindowProc( arguments );

Hi Endurion, thanks for your reply. Sorry I should have showed my whole WindowProc:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

//Textout output
wchar_t text[] = L"tess test test";

TextOut(hdc, 1, 1, text, ARRAYSIZE(text));
//Textout output end

//FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

EndPaint(hwnd, &ps);
}
return 0;

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

Once I include my graphics class, DirectX will do the drawing, but for now I just want to work with testing values. I cant quite work how how to use WM_ERASEBKGND to avoid flickering? I thought the false flag in InvalidateRect should do this?

Thanks

Advertisement

You can use OutputDebugString() which will print to your console window in the debugger if you are using Visual Studio or you can see this by using DebugView without a debugger.

When dealing with GDI as TextOut is you need a WM_PAINT or similar message to update the screen in.

Hi, thanks for your response. I am a bit confused first of all. I don't seem to have a 'console' window, just the win32 window that the demo creates, so I dont know where this output goes? I will have a look into DebugView.

It's been quite awhile since I've written a Win32 game but if I'm not mistaken, calling InvalidateRect() causes a WM_Paint messages to be sent. Setup a timer to periodically call InvalidateRect() and you should see your text output update. You'll probably want to store that hwnd value from when you create the window so that you'll have access to it for the first parameter. You can use a NULL for the rect parameter to paint the entire window's contents and then it's just whether you want to erase the current contents of the window or not.

Thank you, I have kind of got it to work. I am seeing the debug text flicker on the screen, as if it is getting overwritten with a blank white fill or something... I am not sure why. Win32 stuff is so confusing...

My message loop now looks like this

while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
game.run(hwnd);
InvalidateRect(hwnd, NULL, false);
}
}

with WM paint

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

//Textout output
wchar_t text[] = L"tess test test";

TextOut(hdc, 1, 1, text, ARRAYSIZE(text));
//Textout output end

//FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

EndPaint(hwnd, &ps);
}

When FillRect is not commented out the screen stays white. Thanks for all your help guys.

Your console window is the output window in Visual Studio, were you can see which Dlls and symbols are loaded on application start up.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

There's other possibilities for WM_ERASEBKGND to fire than InvalidateRect calls (moving the window off screen and back on screen for example).

The handler for doing nothing is simple:


case WM_ERASEBKGND:
  return 1;

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

There's other possibilities for WM_ERASEBKGND to fire than InvalidateRect calls (moving the window off screen and back on screen for example).

The handler for doing nothing is simple:


case WM_ERASEBKGND:
  return 1;

Hi Endurion,

I have added that but I am still getting the flickering. If i resize or move the window indeed my text does no flicker, but it does when I do nothing...


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	case WM_ERASEBKGND:
		return 1;

	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hwnd, &ps);

		//Textout output
		wchar_t text[] = L"test test test";

		TextOut(hdc, 1, 1, text, ARRAYSIZE(text));
		//Textout output end

		//FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

		EndPaint(hwnd, &ps);
	}
	return 0;

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

Sorry guys, I have tried everything I have read online so am a bit stuck with this...

Thanks

The flicker is inevitable if you first draw a background, then draw the text. The only way to be truly flicker free is to draw the background and then the text to an offscreen buffer, then draw the offscreen buffer to the screen in one go.

Otherwise there is a brief period where the background has been drawn but the text has not been.

When you are using DirectX this will all be handled for you. You'll be by-default drawing to an offscreen buffer which will then be dumped to the screen in one go. You can simulate it using the Win32 API but if you are planning to switch to DirectX at some point anyway, I wouldn't worry.

This topic is closed to new replies.

Advertisement