Results 1 to 4 of 4

Thread: DirectX 9, ALT-TAB and mode changes?

  1. #1

    DirectX 9, ALT-TAB and mode changes?

    Hi,

    I'm currently programming 2D game by using DirectX ID3DXSprite interface. I have created window by using CreateWindow() function and I have message handler and a message loop up and running. So, skeleton for the rendering is ready and working, but....

    If I want to do so, that user can press ALT-ENTER to switch between windowed and fullscreen mode. What I have to do? I know I should read proper messages for when the keys is pressed - okey, but then what? Set the size of window somehow (SetWindowLong()) by how? And what about DirectX? Should I stop rendering (which occurs in message loop). How to do that?

    And what about if I'm rendering fullscreen and user presses ALT-TAB or "windows logo" key? How to handle situation like that?

    I have tried to find tutorials, but these are very hard to find for DirectX 9.

    I appreciate your answers - thanks.
    - In a world without the wall and fences, who will need the Gates and Windows.

  2. #2

    DirectX 9, ALT-TAB and mode changes?

    What the heck I'm doing wrong? I'm trying to avoid a lost device when alt-tabbing a fullscreen application.

    I have BeginScene function which is called begining of main loop. In BeginScene function I check for lost device with TestCooperativeLevel function. If device is lost BeginScene returns result of TestCooperativelevel and exists.

    In main loop, when calling the BeginScene I check if it fails and then it doen't enter in the game loop. And when the BeginScene is called again. I check the CooperativeLevel (of course) and if it's "device no reset" state I reset the device, return "failure" to main loop and exit from function.

    And next time, when main loop calls BeginScene all should be fine and rendering should occur, but that never happens. What I'm doing wrong?

    Code:
    function BeginScene: HRESULT;
    var
      hr: HRESULT;
    begin
    
      hr := Device.TestCooperativeLevel;
    
      if hr = D3DERR_DEVICELOST then begin
        Result := hr;
        Exit;
      end;
    
      if hr = D3DERR_DEVICENOTRESET then begin
        Device.Reset(FD3DPP);
        Result := hr;
        Exit;
      end;
    
      Device.Clear(0, nil, D3DCLEAR_TARGET, $000000, 1, 0);
    
      Result := Device.BeginScene;
    end;
    
    
    While uMsg <> WM_QUIT do begin
        if GameWindow.Active then
          MsgWaiting &#58;= PeekMessage&#40;uMsg, 0, 0, 0, PM_REMOVE&#41;
        else
          MsgWaiting &#58;= GetMessage&#40;uMsg, 0, 0, 0&#41;;
    
        if MsgWaiting then begin
          TranslateMessage&#40;uMsg&#41;;
          DispatchMessage&#40;uMsg&#41;;
          Continue;
        end;
    
        GameTimer.Update;
    
        // Check if we could begun 3D drawing.
        if GameDX.BeginScene = D3D_OK then begin
          
         // Game code here. If application is ALT-TABed then this is section is never ran.
    
          GameDX.EndScene;
        end; 
    end;
    - In a world without the wall and fences, who will need the Gates and Windows.

  3. #3

    DirectX 9, ALT-TAB and mode changes?

    This is how I handle changing from full-screen to windowed and back.

    When I detect the key-press to switch modes, I set the Windowed property as appropriate and call the Reset method of my TDK3DDevice object.
    [pascal]procedure TDK3DDevice.Reset;
    var
    d3dpp: TD3DPresentParameters;
    begin
    DoDeviceReset;
    FillPresentParameters(d3dpp);
    Assert(FDevice.Reset(d3dpp) = D3D_OK);
    DoDeviceLost;
    end;[/pascal]
    DoDeviceReset triggers the OnDeviceReset event of the TDK3DDevice object. In the event handler for OnDeviceReset, I invalidate any loaded resources that require invalidating and change the window style.
    [pascal]procedure TfrmMain.DeviceReset(Sender: TObject);
    begin
    gSystem.Fonts.InvalidateDeviceObjects;

    if gSystem.Device.Windowed then
    begin
    BorderStyle := FWindowedBorderStyle;
    Left := FWindowedLeft;
    Top := FWindowedTop;
    end
    else
    begin
    FWindowedBorderStyle := BorderStyle;
    FWindowedLeft := Left;
    FWindowedTop := Top;

    BorderStyle := bsNone;
    Left := 0;
    Top := 0;
    end;

    gSystem.Device.WindowHandle := Handle;

    ClientWidth := gSystem.Device.Width;
    ClientHeight := gSystem.Device.Height;
    end;[/pascal]
    The only resources I have that require invalidating are the font objects.
    [pascal]procedure TDKFont.InvalidateDeviceObjects;
    begin
    m_pVB := nil;
    m_pSavedStateBlock := nil;
    m_pDrawTextStateBlock := nil;
    end;[/pascal]
    Here it destroys the vertex buffer and state blocks.

    In the OnDeviceLost event handler, I restore the objects that were destroyed previously.
    [pascal]procedure TfrmMain.DeviceLost(Sender: TObject);
    begin
    gSystem.Fonts.RestoreDeviceObjects;
    end;[/pascal]
    Again, it is only the font objects that require restoring.
    [pascal]function TDKFont.RestoreDeviceObjects: HRESULT;
    var
    which: LongWord;
    begin
    // Create vertex buffer for the letters
    Result:= m_pd3dDevice.CreateVertexBuffer(MAX_NUM_VERTICES*S izeOf(TFont2DVertex),
    D3DUSAGE_WRITEONLY or D3DUSAGE_DYNAMIC,
    0, D3DPOOL_DEFAULT, m_pVB, nil);
    if FAILED(Result) then Exit;

    // Create the state blocks for rendering text
    for which:= 0 to 1 do
    begin
    m_pd3dDevice.BeginStateBlock;
    FMaterial.Texture.Use(m_pd3dDevice);

    if FZEnable then
    m_pd3dDevice.SetRenderState(D3DRS_ZENABLE, iTrue)
    else
    m_pd3dDevice.SetRenderState(D3DRS_ZENABLE, iFalse);

    m_pd3dDevice.SetRenderState(D3DRS_ALPHABLENDENABLE , iTrue);
    m_pd3dDevice.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    m_pd3dDevice.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    m_pd3dDevice.SetRenderState(D3DRS_ALPHATESTENABLE, iFalse);
    m_pd3dDevice.SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
    m_pd3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
    m_pd3dDevice.SetRenderState(D3DRS_STENCILENABLE, iFalse);
    m_pd3dDevice.SetRenderState(D3DRS_CLIPPING, iTrue);
    m_pd3dDevice.SetRenderState(D3DRS_MULTISAMPLEANTIA LIAS, iFalse);
    m_pd3dDevice.SetRenderState(D3DRS_CLIPPLANEENABLE, iFalse);
    m_pd3dDevice.SetRenderState(D3DRS_VERTEXBLEND, iFalse);
    m_pd3dDevice.SetRenderState(D3DRS_INDEXEDVERTEXBLE NDENABLE, iFalse);
    m_pd3dDevice.SetRenderState(D3DRS_FOGENABLE, iFalse);

    m_pd3dDevice.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
    m_pd3dDevice.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    m_pd3dDevice.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
    m_pd3dDevice.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
    m_pd3dDevice.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
    m_pd3dDevice.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

    m_pd3dDevice.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
    m_pd3dDevice.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
    m_pd3dDevice.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);

    m_pd3dDevice.SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
    m_pd3dDevice.SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
    m_pd3dDevice.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
    m_pd3dDevice.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

    if (which = 0) then
    m_pd3dDevice.EndStateBlock(m_pSavedStateBlock)
    else
    m_pd3dDevice.EndStateBlock(m_pDrawTextStateBlock);
    end;

    Result:= S_OK;
    end;[/pascal]
    This method recreates the vertex buffer and the state blocks used by the fonts.

    This means that with those methods in place, to switch modes all I do is the following:
    [pascal] gSystem.Device.Windowed := not gSystem.Device.Windowed;
    gSystem.Device.Reset;[/pascal]
    This allows me to switch back and forth from windowed to full-screen as much as I want. Note that I have not handled the case where the call to BeginScene fails yet due to Alt+Tab. That is yet to be done.

    Hope that helps a bit.

  4. #4

    DirectX 9, ALT-TAB and mode changes?

    Quote Originally Posted by Sly
    This is how I handle changing from full-screen to windowed and back.

    Hope that helps a bit.
    Thank you Sly again for your help. I finally managed to get it work. Now I can ALT-TAB or press "logokey" to change my application to idle mode and reset it back to working state.

    I Also got ALT-ENTER combination to work. The problem was that I assumed that, when I set window properties with GetWindowLong() WinAPI function (I don't use VCL components) it automaticly looses my device, but that didn't happend. So I have to call Reset() by my self.

    Thanks very mutch.
    - In a world without the wall and fences, who will need the Gates and Windows.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •