Sign in to follow this  
kamal7

Resetting sprites after ALT+TAB

Recommended Posts

I am having trouble resetting sprites after alt+tab unless I reinitialize them which I don't want to do because it slows down everything. Here is my code:

In WinMain.cpp here is the alt+tab detection and reset devices external command:
[code]
LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_ACTIVATEAPP:
if (wParam) m_pGame->DxDraw.ResetDevice(); // Reset devices after alt+tab
break;
}
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
[/code]

DxDraw.cpp:
[code]
#include "DxDraw.h"

extern bool bWindowed;
extern int m_iMaxRes_X, m_iMaxRes_Y, wx, wy;
extern HWND g_hWnd;

CDxDraw::CDxDraw()
{ int i;

g_pDirect3D = NULL;
g_pD3DDevice = NULL;
m_pFont = NULL;
for (i = 0; i < DEF_MAXSPRITES; i++) m_pSprite[i] = NULL;
}

CDxDraw::~CDxDraw()
{ int i;

for (i = 0; i < DEF_MAXSPRITES; i++)
if (m_pSprite[i] != NULL) delete m_pSprite[i];

m_pFont->Release();
g_pD3DDevice->Release();
g_pDirect3D->Release();
}

HRESULT CDxDraw::DX3DInit(DWORD iWidth, DWORD iHeight)
{
if ((g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL){
MessageBox(g_hWnd, "Direct3D create interface pointer is undefined.", "ERROR!", MB_OK);
return 0;
}

ZeroMemory(&d3dpp, sizeof(d3dpp));

d3dpp.BackBufferWidth = iWidth;
d3dpp.BackBufferHeight = iHeight;
d3dpp.hDeviceWindow = g_hWnd; // set the window to be used by Direct3D
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; // set the back buffer format: D3DFMT_A16B16G16R16 = 64-bit (unavailable), D3DFMT_A8R8G8B8 = 32-bit with alpha channel
d3dpp.BackBufferCount = 1;
d3dpp.Windowed = bWindowed; // program windowed or fullscreen

// Windowed Mode
if (bWindowed) d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
else { // Fullscreen Mode
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP; // discard old frames
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
}

HRESULT hRes;
if(FAILED(hRes = g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice))) return hRes;

float Aspect = (float)d3dpp.BackBufferWidth / (float)d3dpp.BackBufferHeight;
D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&matProjection, D3DX_PI/4.0f, Aspect, 0.001f, 1000.0f);
g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProjection);
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

D3DXCreateFont(g_pD3DDevice, 13, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Tahoma"), &m_pFont);

return S_OK;
}

void CDxDraw::BeginRender()
{ int i;
if (g_pD3DDevice == NULL) return;

// Clear the backbuffer to a black color
g_pD3DDevice->Clear( 0, //number of rectangles to clear, 0 for all
NULL, //rects to be cleared, NULL for entire buffer
D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, //the buffers to clear
D3DCOLOR_XRGB(255,255,255), //the Color to fill the buffer with
1.0f, //depth for the z-buffer to clear
0 //stencil buffer clear
);

g_pD3DDevice->BeginScene();

for (i = 0; i < DEF_MAXSPRITES; i++)
if (m_pSprite[i] != NULL) m_pSprite[i]->render(100);
}

void CDxDraw::EndRender()
{
//Notify the device that we're finished rendering for this frame
g_pD3DDevice->EndScene();

//Show the results
g_pD3DDevice->Present(NULL, //Source rectangle to display, NULL for all of it
NULL, //Destination rectangle, NULL to fill whole display
NULL, //Target window, if NULL uses device window set in CreateDevice
NULL //Unused parameter, set it to NULL
);
}

void CDxDraw::bInit()
{
m_pSprite[0] = new class CSprite(g_pD3DDevice,"1_b.jpg", 0, 0, wx, wy);
m_pSprite[1] = new class CSprite(g_pD3DDevice,"logo.png", 15, 0, 290, 240);
}

void CDxDraw::DisplayText(char *pString, short sX, short sY, short sMaxW_X, short sMaxL_Y, short sA, short sR, short sG, short sB)
{
// Create a rectangle to indicate where on the screen it should be drawn
RECT rct;
rct.left = sX;
rct.top = sY;

//Set default rectangle coordinates (hidden)
m_pFont->DrawText(NULL, pString, -1, &rct, DT_CALCRECT | DT_WORDBREAK | DT_SINGLELINE, NULL);

//Determine if align is required and set max rectangle rct.right(x)/rct.bottom(y) coordinates.
if (sMaxW_X != -1) rct.right = rct.left+sMaxW_X;
if (sMaxL_Y != -1) rct.bottom = rct.top+sMaxL_Y;

//Draw text in set rectangle coordinates
m_pFont->DrawText(NULL, pString, -1, &rct, DT_WORDBREAK | DT_SINGLELINE | DT_CENTER | DT_VCENTER, D3DCOLOR_ARGB(sA,sR,sG,sB)); //D3DCOLOR_ARGB(alpha,red,green,blue)
}

void CDxDraw::ResetDevice()
{ int i;

for (i = 0; i < DEF_MAXSPRITES; i++)
if (m_pSprite[i]) m_pSprite[i]->OnLostDevice();

if (m_pFont) m_pFont->OnLostDevice();
if (g_pDirect3D) g_pDirect3D->Release();
if (g_pD3DDevice) g_pD3DDevice->Release();

if (DX3DInit(wx, wy) != S_OK)
{
MessageBox(g_hWnd, "Initialization error.", "ERROR!", MB_OK);
return;
}
//g_pD3DDevice->Reset(&d3dpp);

for (i = 0; i < DEF_MAXSPRITES; i++)
if (m_pSprite[i]) m_pSprite[i]->OnResetDevice();

m_pSprite[0]->OnResetDevice();
m_pFont->OnResetDevice();
//bInit(); // Reinitializes the sprites... something I don't want to do.
}
[/code]

My Sprite.cpp... this is where I draw the sprites.
[code]
#include <windows.h>
#include "Sprite.h"

// FUNCTION: CSprite(LPDIRECT3DDEVICE9 device, std::string filename)
// PURPOSE: constructor for the 2d Sprite class | create a D3DXSprite and loads it with an image | sets the destination position on the screen, x and y are the top left corner | sets size the image width and height
CSprite::CSprite(LPDIRECT3DDEVICE9 device, std::string filename, int x, int y, int newWidth, int newHeight)
{
sprite = NULL;
texture = NULL;

D3DXCreateSprite(device, &sprite);

D3DXCreateTextureFromFileEx(device, filename.c_str(), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, D3DX_FILTER_NONE, D3DX_DEFAULT, 0, NULL, NULL, &texture);

D3DXIMAGE_INFO imageInfo;
D3DXGetImageInfoFromFile(filename.c_str(), &imageInfo);

position.x = (float)x;
position.y = (float)y;
position.z = 0.0f;

if ((newWidth == NULL) || (newHeight == NULL)) {
scale.x = 1.0f;
scale.y = 1.0f;
}else {
scale.x = (float)newWidth/(float)imageInfo.Width;
scale.y = (float)newHeight/(float)imageInfo.Height;
}
scale.z = 0;
}

// FUNCTION: ~CSprite()
// PURPOSE: deconstructor for the 2d Sprite class
CSprite::~CSprite()
{
}

// FUNCTION: render(LPDIRECT3DDEVICE9 pDevice)
// PURPOSE: draws the sprite
void CSprite::render(int alpha)
{
alpha = (int)(255*((float)alpha/100));
D3DXMATRIX scaleMatrix;
D3DXMATRIX transMatrix;
D3DXMatrixScaling(&scaleMatrix, scale.x, scale.y, scale.z);
D3DXMatrixTranslation(&transMatrix, position.x, position.y, position.z);

D3DXMatrixMultiply(&transMatrix, &scaleMatrix, &transMatrix);
sprite->SetTransform(&transMatrix);

sprite->Begin(D3DXSPRITE_ALPHABLEND);
sprite->Draw(texture, NULL, NULL, NULL, D3DCOLOR_RGBA(255,255,255,alpha));
sprite->End();
}

void CSprite::OnLostDevice()
{
sprite->OnLostDevice();
}

void CSprite::OnResetDevice()
{
sprite->OnResetDevice();
}
[/code]

If anyone can help or would like more detail please respond. Thank you in advance!

Sincerely,
Kamal.

Share this post


Link to post
Share on other sites
Also, alt-tab is far from the only condition that can cause a lost device. Handling lost devices in WM_ACTIVATEAPP is never a good idea; do it the way the documentation recommends by checking for D3DERR_DEVICELOST in your Present call instead.

Share this post


Link to post
Share on other sites
Alright i've updated my code upon your suggestions.. however as usual the font works but the sprites still don't show up.

Updates/Replacements:
[code]
D3DXCreateTextureFromFileEx(device, filename.c_str(), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, 0, NULL, NULL, &texture);
[/code]

[code]
case WM_ACTIVATEAPP:
if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) bProgramActive = TRUE;
else bProgramActive = FALSE;
break;
[/code]

[code]
hr=g_pD3DDevice->Present(NULL, NULL, NULL, NULL);

if (hr == D3DERR_DEVICELOST && bProgramActive) {
while (1) {
hr=g_pD3DDevice->TestCooperativeLevel();
switch (hr) {
case D3D_OK:
ResetDevices();
return;
case D3DERR_DEVICELOST:
ReleaseDevices();
break;
case D3DERR_DEVICENOTRESET:
if (DX3DInit(wx, wy) != S_OK)
{
MessageBox(g_hWnd, "Initialization error.", "ERROR!", MB_OK);
}
g_pD3DDevice->Reset(&d3dpp);
break;
case D3DERR_DRIVERINTERNALERROR:
MessageBox(g_hWnd, "Internal driver error.\nThis program will now exit.", "ERROR!", MB_OK);
SendMessage(g_hWnd, WM_DESTROY, NULL, NULL);
break;
/*default:
MessageBox(g_hWnd, "Failed to render the scene.", "ERROR!", MB_OK);
break;*/
}
Sleep(100);
}
}
[/code]

[code]
void CDxDraw::ReleaseDevices()
{ int i;

/*for (i = 0; i < DEF_MAXSPRITES; i++)
if (m_pSprite[i] != NULL) m_pSprite[i]->OnLostDevice();*/
m_pSprite[0]->OnLostDevice();
//m_pSprite[1]->OnLostDevice();
if (m_pFont) m_pFont->OnLostDevice();
if (g_pDirect3D) g_pDirect3D->Release();
if (g_pD3DDevice) g_pD3DDevice->Release();
}

void CDxDraw::ResetDevices()
{ int i;
/*for (i = 0; i < DEF_MAXSPRITES; i++)
if (m_pSprite[i] != NULL) m_pSprite[i]->OnResetDevice();*/
m_pSprite[0]->OnResetDevice();
//m_pSprite[1]->OnResetDevice();
m_pFont->OnResetDevice();
//bInit();
}
[/code]

I've been reading everywhere on what may be the problem, however I have no clue as to why the problem persists.

PS. Is there any way to add an image into my project workspace so I can read images in Debug Runtime to check the output issues in fullscreen (since window mode seems to work, although it worked even without resetting the devices).

Share this post


Link to post
Share on other sites
I found out D3DERR_DEVICELOST is not being called from TestCooperativeLevel(). Any suggestions or comments?

Share this post


Link to post
Share on other sites
You don't need bProgramActive at all. The device will be automatically lost if you alt-tab away and TestCooperateLevel will give the correct hr when you alt-tab back; WM_ACTIVATEAPP is completely unnecessary for this procedure. All that you need is a test for if (hr == D3DERR_DEVICELOST).

I'm not sure why you're calling DX3DInit from your loss handler; is there anything special in there? All you should need to do is release and then recreate non-managed resources; running through what looks like the full init code again seems too much.

I'd also move your ReleaseDevices call to the D3DERR_DEVICENOTRESET condition, just before calling Reset.

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