• Advertisement
Sign in to follow this  

Game thread and rendering

This topic is 3316 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to handle the 'alt-tab' event. I read the article at: http://www.gamedev.net/reference/articles/article1249.asp and I got scared. (For those of you who don't want to go to the link, it's about how to use a thread for the message pump and a thread for the game code.) It seemed like it would put problem into a box with a nice bow on it, but I know NOTHING about threads (well, some of the theory but no actual hands on experience). But I figured nothing lost, nothing gained so I gave it a shot (after copying my code). But I have a problem. I'm currently working on rendering some basic opening credits at the beginning of the game. My current credit is a basic line of white characters fading in (alpha from 0 to some number, say 255 for simplicity) on a black background. When I alt-tab during the rendering, I have some elements of the desktop come up and stay up (these differ from run time to run time (sometimes its the tab bar in the center of the screen, the windows button on the bottom left, the taskbar on the bottom, etc) and they flicker (go from themselves to black to back again until the rendering ends). But the credit itself isn't effected. Here's my code (it's pretty ugly, it doesn't quite fit in the box but I tried to make it more readable). DWORD WINAPI GameThread(LPVOID arg1) { // This is the game thread. All the code for running the game goes here. // Local variables: int height; string name; int width; const string settingsFile = "settings\\settings.xml"; // Retrieves the system settings (uses tinyXML to read file). getSystemSetttings(settingsFile, &name, &height, &width); // Creates the game's resources (window, directX, etc). GameWindow window(name.c_str(), width, height); window.create(); DirectGraphics graphics(&window); DirectInput input(window.getHandle()); // Creates & displays the opening credits. displayOpeningCredits(&graphics); // Closes window. PostMessage(window.getHandle(), WM_CLOSE, 0, 0); return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { /* This is were the game begins its execution. The game thread is created (handles all the code for the game) and the message pump is handled here. */ // Local variables: HANDLE gameThreadHandle; DWORD threadId; // Creates the game thread. gameThreadHandle = CreateThread(0, 0, &GameThread, 0, 0, &threadId); // Enters the message pump. MSG msg; while (true) { // Checks to see if there's a message waiting in the queue if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // If the message is WM_QUIT, exits the loop if (msg.message == WM_QUIT) break; // Translates keystroke messages into the correct . TranslateMessage(&msg); // Sends the message to the WindowProc function DispatchMessage(&msg); } } // Returns this part of the WM_QUIT message to Windows. return msg.wParam; } void displayOpeningCredits(DirectGraphics* directGraphics) { /* This is the main function for the opening credits. It creates the opening credits as a linked list and renders the credits. */ // Local variables: ID3DXFont* creditFont; /* Creates the font for the credits (simply calls D3DXCreateFont and returns the created font). */ creditFont = createOpeningCreditFont(directGraphics->getDevice()); // Creates a temp credit to test. Credit a(creditFont, directGraphics); a.readOpeningCredit("credits\\opening\\producer.xml"); a.render(); The 'readOpeningCredit' member function reads the given file and stores the infomation inside the object via tinyXML. The 'render' member compares a stored variable in the object to different rendering options and calls the corresponding member function. In this case 'renderFadeIn' is called. void Credit::renderFadeIn() const{ /* Renders the credit fading in, taking as long as the stored amount of time (renderTime_). The credit starts with an alpha value of 0 and stops at the stored alpha value. */ // Frame rate variable: const float frameRate = (float)1/60; // Alpha variables: const float alphaChange = (this->fontAlpha_ / this->renderTime_) * frameRate; float currentAlpha = 0; const int maxAlpha = this->fontAlpha_; // Direct graphics variables: HRESULT deviceState; IDirect3DDevice9* graphics = this->directGraphics_->getDevice(); // Font variables: const int blue = this->fontBlue_; const char* credit = this->caption_.c_str(); const int green = this->fontGreen_; const int length = this->caption_.length(); const int red = this->fontRed_; RECT textbox = this->location_; // Time variables: int lastFrameTime; // Fades the credit in. while (currentAlpha <= maxAlpha) { // Checks if the direct graphics device has lost control of the display. deviceState = graphics->TestCooperativeLevel(); while(deviceState == D3DERR_DEVICELOST) { this->font_->OnLostDevice(); deviceState = graphics->TestCooperativeLevel(); } while(deviceState == D3DERR_DEVICENOTRESET) { deviceState = graphics->Reset(&this->directGraphics_->getInfomation()); if(SUCCEEDED(deviceState)) { this->font_->OnResetDevice(); deviceState = graphics->TestCooperativeLevel(); } } // Updates the current alpha value. currentAlpha += alphaChange; // Renders the credit with the current alpha value. graphics->BeginScene(); this->font_->DrawText(NULL, credit, length, &textbox, DT_TOP | DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB((int)currentAlpha, red, green, blue)); graphics->EndScene(); graphics->Present(NULL, NULL, NULL, NULL); lastFrameTime = GetTickCount(); // Frame rate controller. while (GetTickCount() - lastFrameTime <= frameRate) ; } } DirectGraphics is a C++ class wrapper for the direct3D variables (interface, device and the infomation struct variables with functions to return those variables). If my code is confusing (probably is without the full code and documentation and the limited box size I have to type/copy things into) I'd settle for a great tutorial.

Share this post


Link to post
Share on other sites
Advertisement
The start of my render function looks like so:

   if(dx.screen == NULL){
return;
}

// Handle alt-tab/lost device
static HRESULT result;
result = dx.screen->TestCooperativeLevel();
switch(result){
case D3D_OK:
break;
case D3DERR_DEVICELOST:
return;
case D3DERR_DEVICENOTRESET:
dx.reset();
return;
case D3DERR_DRIVERINTERNALERROR:
return;
}





Be sure to destroy and recreate any fragile resources after an alt-tab returns.

On a different note, I like to do timing in the main loop. This is older code (I use a timer class) but it serves to show better than a class would. The advantages are that with a class it is easy to have a separate AI timer so that AI isn't recalculated every frame. elapsedSeconds is passed to the render function, to update positions, and the like.
    // To maintain a steady 30 fps
static LARGE_INTEGER prevTick, currentTick, elapsedTicks, timerTicksPerSecond;
QueryPerformanceFrequency( &timerTicksPerSecond );
QueryPerformanceCounter( &prevTick );
float elapsedSeconds;

PeekMessage(&message,NULL, 0U, 0U, PM_NOREMOVE);

while(message.message != WM_QUIT)
{
if( PeekMessage( &message, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage ( &message );
DispatchMessage ( &message );
}
Sleep(1);
// Explored: SwitchToThread(): CPU usage varied widely 7%~85%
// Multimedia timers: XP only
// Sleep(0): CPU usage 100%

// Calculate elapsed time
QueryPerformanceCounter(&currentTick);
elapsedTicks.QuadPart = currentTick.QuadPart - prevTick.QuadPart;
elapsedSeconds = (float) elapsedTicks.QuadPart / timerTicksPerSecond.QuadPart;

if( elapsedSeconds >= 0.03) // 30 frames/second ~= 0.03 seconds/frame
{
prevTick = currentTick;
render_scene(elapsedSeconds); // execute the render function
}

}// while !WM_QUIT

return message.wParam; // value sent through PostQuitMessage()
};



Share this post


Link to post
Share on other sites
Okay so I made some minor alterations to my code but I still have the 'flickering' issue.

Here's my altered code:




In my 'fadeIn' member function for my credit object:
.
.
.

// Checks if the direct graphics device has lost control of the display.
deviceState = graphics->TestCooperativeLevel();
switch(deviceState) {
case D3D_OK:
break;
case D3DERR_DRIVERINTERNALERROR:
MessageBox(NULL, deviceError.c_str(), errorTitle.c_str(), MB_ICONERROR | MB_OK);
exit(error);
case D3DERR_DEVICELOST:
this->font_->OnLostDevice();
case D3DERR_DEVICENOTRESET:
graphics->Reset(&this->directGraphics_->getInfomation());
this->font_->OnResetDevice();
break;
}
.
.
.




In my game thread:

DWORD WINAPI GameThread(LPVOID arg1) {
// This is the game thread. All the code for running the game goes here.

// Local variables:
int height;
string name;
int width;
const string settingsFile = "settings\\settings.xml";

// Retrieves the system settings.
getSystemSetttings(settingsFile, &name, &height, &width);

// Creates the game's resources (window, directX, etc).
GameWindow window(name.c_str(), width, height);
window.create();
DirectGraphics graphics(&window);
DirectInput input(window.getHandle());

// Creates & displays the opening credits.
displayOpeningCredits(&graphics);

// Clean up.
DestroyWindow(window.getHandle());
::isMessagePumpActive = false;

return 0;



My message pump thread:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
/* This is were the game begins its execution. The game thread is created (handles all the code
* for the game) and the message pump is handled here. */

// Local variables:
HANDLE gameThreadHandle;
MSG message;
DWORD threadId;

// Creates the game thread.
gameThreadHandle = CreateThread(0, 0, &GameThread, 0, 0, &threadId);

// Activates the message pump.
::isMessagePumpActive = true;

// Enters the message pump.
while (::isMessagePumpActive == true) {

// Checks to see if there's a message waiting in the queue
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {

// Message checks here.

// Translates keystroke messages into the correct .
TranslateMessage(&message);

// Sends the message to the WindowProc function
DispatchMessage(&message);
}
}

return 0;
}



I forgot before but this is my windowProc function as well:
LRESULT CALLBACK WindowProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) {
// Sorts through to find what code to run for the given message.

// Local variables:
const int sleepLength = 10;

// The message handler.
switch(message) {

// Checks for system commands (window being minimized, maximized, etc).
case WM_SYSCOMMAND:
switch(wParam) {

// Checks if the window has been minimized.
case SC_MINIMIZE:
Sleep(sleepLength);
break;

// Checks if the window has been maximized.
case SC_MAXIMIZE:
break;
}


// This message is read when the window is closed, it closes the appiccation entirely.
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}

break;
}

// Handles any messages the switch statement didn't.
return DefWindowProc (windowHandle, message, wParam, lParam);
}



I found out also that if I have another window in the background (such as an internet browser) when I alt-tab during the rendering the background window pops up but the screen flickers between it and the black background of the credit (the credit itself isn't affected, it just stays up there). It kind of seems like when I alt-tab the direct3D device refuses to lose the display and the windows OS is fighting for the display.

EDIT:
Okay so after some further testing I've found out that the 'flickering' is in time with my rendering loop. IE I made another render type (typewriter) that basically 'types' the credit onto the screen like a typewriter. It renders each letter on screen at a time of (total rendering time / credit length).
Lets say this is 2 seconds (every 2 seconds another letter is rendered). If I 'alt-tab' during the rendering, I go from my game with 1 letter rendered to the background window (or parts of the desktop if there's no background window) with 2 letters rendered, back to my game with 3 letters rendered, back to the window/desktop with 4 letters rendered, etc. And again my credit stays up there, even when the background window or parts of the desktop are showing.

[Edited by - Gamer Pro on December 24, 2008 10:37:22 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement