Page 1 of 1

DirectX + Alt + Tab

Posted: Fri Dec 18, 2009 7:58 pm
by blueznl
After searching through these forums, and browsing the game section, and reading the FAQ, I still do not have a fail safe solution...

I want to be able to Alt+Tab from a full screen PureBasic application back to the desktop, and then back to my application, without the application crashing... How do I o that?

Re: DirectX + Alt + Tab

Posted: Fri Dec 18, 2009 8:02 pm
by Kaeru Gaman
should work flawlessly... pse state an example that doesn't...

Re: DirectX + Alt + Tab

Posted: Fri Dec 18, 2009 8:04 pm
by blueznl
I am not sitting behind my machine right now, but I will do so tonight, yesterday every attempt at Alt+Tab crashed the application. Perhaps I screwed up? (I do sometimes, you know, that's how I ended up married :-))

Re: DirectX + Alt + Tab

Posted: Fri Dec 18, 2009 8:07 pm
by Kaeru Gaman
I'm not sure if there was a problem with calling FlipBuffers or ScreenOutput when the screen is inactive, whether we have to if it out or not...
but when you put everything concerning the screen after an If IsScreenActive and only a Delay after the Else, it should become rocksolid.

Re: DirectX + Alt + Tab

Posted: Fri Dec 18, 2009 8:37 pm
by blueznl
Well, it's an answer, but somewhat, euh... vague :-)

Could you modify the code below to show me what you mean? I'm clueless...

Code: Select all

InitKeyboard()
InitSprite()
InitSprite3D()
;
OpenScreen(1024,768,32,"Test",#PB_Screen_SmartSynchronization)
;
CreateImage(1,100,100,32)
StartDrawing(ImageOutput(1))
  DrawingMode(#PB_2DDrawing_AlphaChannel)
  Box(0,0,100,100,0)
  DrawingMode(#PB_2DDrawing_AlphaBlend)
  BackColor(RGBA(0,0,0,0))
  FrontColor(RGBA(255,255,255,255))
  LineXY(4,95,49,5)
  LineXY(5,95,50,5)
  LineXY(50,5,95,95)
  LineXY(51,5,96,95)
  LineXY(95,95,50,85)
  LineXY(95,96,50,86)
  LineXY(50,85,5,95)
  LineXY(50,86,5,96)
  FillArea(45,20,-1,RGBA(255,0,0,96))
  LineXY(50,6,50,84,RGBA(128,128,128,96))
  FillArea(55,20,-1,RGBA(128,128,128,255))
StopDrawing()
;
CreateSprite(1,100,100,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(1))
  DrawImage(ImageID(1),0,0)
StopDrawing()
CreateSprite3D(1,1)
;
s = 5
a = 0
Repeat
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape)
    event = #PB_Event_CloseWindow
  EndIf
  If event = 0
    ClearScreen(0)
    For y = 0 To 1
      For xx = 0 To 1
        For x = 0 To 7
          RotateSprite3D(1,angle,#PB_Absolute)
          Start3D()
            Sprite3DBlendingMode(s,xx*8+x)
            DisplaySprite3D(1+a,30+x*125,10+xx*170+y*410)
            DisplaySprite3D(1+a,50+x*125,30+xx*170+y*410)
          Stop3D()
          StartDrawing(ScreenOutput())
            DrawingMode(#PB_2DDrawing_Transparent)
            DrawText(60+x*125,150+xx*170+y*410,Str(s)+" , "+Str(xx*8+x),RGB(255,255,255)*(1-y))
          StopDrawing()
        Next x
      Next xx
    Next y
    angle = (angle+1) % 360
    FlipBuffers()
  EndIf
Until event = #PB_Event_CloseWindow
;
CloseScreen()

Re: DirectX + Alt + Tab

Posted: Sat Dec 19, 2009 12:59 am
by STARGÅTE

Re: DirectX + Alt + Tab

Posted: Sat Dec 19, 2009 1:41 am
by Kaeru Gaman
I'll read that code tomorrow, watching The Closer atm and Black Cristmas afterwards.
gnight

Re: DirectX + Alt + Tab

Posted: Sat Dec 19, 2009 7:05 am
by Demivec
STARGÅTE wrote:same problem as here:
http://www.purebasic.fr/english/viewtop ... =4&t=35669
I noticed all the same symptoms that were posted in that thread when applying the needed corrections to blueznl's code sample above. The needed corrections were prevented from functioning. :(

The most notable problem was that Flipbuffers() can't be called if the screen isn't active and that IsScreenActive() won't indicate the screen is active again without calling Flipbuffers() to update the status of the screen. :shock:

This observation may apply to the bug-thread dealing with threaded apps also.


@Edit: I incorrectly combined separate symptoms, from each of the solutions I was trying, into the observation I stated above. The problem didn't relate directly to FlipBuffers(). FlipBuffers() appeared to work fine (no faults). The problem was that the screen does not become active again when the program is selected again. When this happens IsScreenActive() always returns '0' and none of the screen functions appear to work. I think this is something the developers will have to remedy.

Re: DirectX + Alt + Tab

Posted: Sat Dec 19, 2009 8:38 am
by blueznl
I found some code in a (french) tutorial from 'B-games'. That code works with DirectX7 but NOT with DirectX9.

Makes me wonder if DirectX9 in PureBasic is yet mature enoug to be used as default...

There's also good news: DirectX7 synchronisation has become much better since previous versions...

Re: DirectX + Alt + Tab

Posted: Mon Dec 21, 2009 11:11 am
by djes
This is a code I've done some months ago showing (among other things) how to do. See and adapt check_lostfocus() procedure.

Code: Select all

;******************************************************************************************************
;* Rasterline and VBL Sync
;* By djes (djes@free.fr) 03/24/2009
;* Thanx to Stefan Moebius for VBL sync examples
;* Note : I do not check functions return codes : I know it's bad!
;* PB 4.3
;* 12/21/09 : PB 4.40
;******************************************************************************************************

#STARS_NB = 50
#D3D_OK = 0

;******************************************************************************************************

Structure D3DRASTER_STATUS
  InVBlank.l
  ScanLine.l
EndStructure

Structure pos
  x.l
  y.l
  speed.l
EndStructure

;******************************************************************************************************

Define.D3DRASTER_STATUS raster
Define.IDirect3DDevice9 D3Ddevice_interface

Dim stars.pos(#STARS_NB)

;******************************************************************************************************
;-                                            PROCEDURES
;******************************************************************************************************
;wait for the vblank to start
;attend le début de la synchro vbl
Procedure vblank_wait()
	Shared D3Ddevice_interface, raster, exit
  Repeat
    ExamineKeyboard()
    If KeyboardPushed(#PB_Key_Escape) 
      exit=#True
    EndIf
    D3Ddevice_interface\GetRasterStatus(0, @raster)
  Until raster\InVBlank=#True Or exit 
EndProcedure

;******************************************************************************************************
;wait for the vblank to finish
;attend la fin de la synchro vbl
Procedure vblank_end_wait()
	Shared D3Ddevice_interface, raster, exit
  Repeat
    ExamineKeyboard()
    If KeyboardPushed(#PB_Key_Escape) 
      exit=#True
    EndIf
    D3Ddevice_interface\GetRasterStatus(0, @raster)
  Until raster\InVBlank=#False Or exit
EndProcedure

;******************************************************************************************************
;récupère la position du raster et y affiche une ligne de la couleur indiquée
Procedure rasterline(color.l)
  Shared raster, D3Ddevice_interface
  StartDrawing(ScreenOutput())
  D3Ddevice_interface\GetRasterStatus(0, @raster)
  LineXY(0, raster\ScanLine, 1023, raster\ScanLine, color)
  StopDrawing()
EndProcedure

;******************************************************************************************************
Procedure create_sprites()
	CreateSprite(0, 64, 64)
	StartDrawing(SpriteOutput(0))
	Circle(32, 32, 31, RGB($FF, $FF, $FF))
	StopDrawing()
EndProcedure

;******************************************************************************************************
;Open screen and get the device - Ouvre l'écran et récupère le device
Procedure init_display()
	Shared *SwapChain_interface, D3Ddevice_interface
	OpenScreen(1024, 768, 32, "", #PB_Screen_NoSynchronization)
	!extrn _PB_Screen_Direct3DDevice
	!MOV dword EAX, [_PB_Screen_Direct3DDevice]
	!MOV dword [v_D3Ddevice_interface],EAX
EndProcedure

;******************************************************************************************************
;Check if the user has switched (and that we have lost focus) (ALT-TAB)
;Vérifie si l'utilisateur n'a pas changé d'appli (en nous faisant donc perdre le focus) (ALT-TAB)
Procedure check_lostfocus()
  
  If IsScreenActive() = 0

		ReleaseMouse(1)

		;we're lowering our priority - on baisse notre priorité
		SetPriorityClass_(  GetCurrentProcess_(), #NORMAL_PRIORITY_CLASS)
		SetThreadPriority_( GetCurrentThread_() , #THREAD_PRIORITY_NORMAL) 
	  
		;Wait til our window is coming back to foreground - Attend que notre fenêtre repasse au premier plan
	  Repeat
	  	;now our events are to be processed with WaitWindowEvent, else IsScreenActive() will never say that our window has the focus again
	  	;it should be written in the doc!
	  	;maintenant les événements sont à gérer avec WaitWindowEvent, sinon IsScreenActive() ne dit jamais que notre fenêtre a à nouveau le focus
	  	;il faudrait mettre ça dans la doc!!!!
	  	WaitWindowEvent()	
	  Until IsScreenActive() <> 0

		ReleaseMouse(0)
		;Better recreate the screen - il vaut mieux recréer l'écran
		CloseScreen()
		init_display()
		;and the sprites too (have to!) - et les sprites aussi (indispensable)
		create_sprites()
		;give to the system some time to rest - laisse un peu le temps au système de récupérer
		Delay(2000)


		;We're waiting for the synchro a new time - On réattend la synchro
		vblank_wait()
		SetPriorityClass_(  GetCurrentProcess_(), #HIGH_PRIORITY_CLASS)
		SetThreadPriority_( GetCurrentThread_() , #THREAD_PRIORITY_ABOVE_NORMAL)     ;warning : keyboard lock

  EndIf

EndProcedure

;******************************************************************************************************
;-                                             INIT
;******************************************************************************************************

InitSprite()
InitKeyboard()
InitMouse()

init_display()
create_sprites()

For i=0 To #STARS_NB-1
  stars(i)\x = Random(1023)
  stars(i)\y = Random(767)
  stars(i)\speed = Random(16) + 1
Next i

exit=#False

;we're giving priority boost to our process - on donne une priorité maximale à notre processus
SetPriorityClass_(  GetCurrentProcess_(), #REALTIME_PRIORITY_CLASS)
SetThreadPriority_( GetCurrentThread_() , #THREAD_PRIORITY_TIME_CRITICAL)     ;warning : keyboard lock

;******************************************************************************************************
;-                                        MAIN LOOP    
;******************************************************************************************************

Repeat

	;wait for the sync - attends la synchro
	vblank_wait()

	;flip the buffers without the PB's sync - flippe le buffer sans utiliser la synchro PB
  FlipBuffers()

	;during VBL, lower a bit our priority to give time to OS (especially to handle the keyboard)
	;pendant la VBL, baisse un peu notre priorité pour donner un peu de temps au système (pour gérer le clavier surtout)
	SetPriorityClass_(  GetCurrentProcess_(), #HIGH_PRIORITY_CLASS)
	SetThreadPriority_( GetCurrentThread_() , #THREAD_PRIORITY_NORMAL)

  ExamineKeyboard()
  ExamineMouse()

  If KeyboardPushed(#PB_Key_Escape) 
    exit=#True
  EndIf

	check_lostfocus()
  ClearScreen(0)
	;we're waiting for the VBL end (could be better!!!)
	;on attend la fin de la VBL (à améliorer) pour être sûr de ne pas sauter une frame
	vblank_end_wait()

	;we're giving priority boost to our process - on donne une priorité maximale à notre processus
	SetPriorityClass_(  GetCurrentProcess_(), #REALTIME_PRIORITY_CLASS)
	SetThreadPriority_( GetCurrentThread_() , #THREAD_PRIORITY_TIME_CRITICAL)     ;warning : keyboard lock



  rasterline($FF0000)


	;-TEST CODE

	;compute our effect
  For i = 0 To #STARS_NB-1
    stars(i)\x + stars(i)\speed
    If stars(i)\x > 1023
      stars(i)\x - 1024 - 64
    EndIf
  Next i

	;draw it
  For i = 0 To #STARS_NB-1
    DisplayTranslucentSprite(0, stars(i)\x, stars(i)\y, stars(i)\speed<<4)
  Next i

	;-END TEST CODE

	;draw a rasterline to see (visually) how much time our fx is taking
	;affiche une rasterline pour visualiser combien de temps prend notre effet
  rasterline($FF00)

Until exit 

CloseScreen()

End

;******************************************************************************************************

Re: DirectX + Alt + Tab

Posted: Mon Dec 21, 2009 11:27 pm
by blueznl
Thx... but this can't be for real, I mean, the idea behind basic is that it's a basic language hiding some complexity from the user... I hope the PBDevs can cook up something that makes this kind of thing easy on the mind of the (beginning) programmer...

Re: DirectX + Alt + Tab

Posted: Tue Dec 22, 2009 9:35 am
by djes
Forget most of the code, just use this :

Code: Select all

;******************************************************************************************************
;Check if the user has switched (and that we have lost focus) (ALT-TAB)
;Vérifie si l'utilisateur n'a pas changé d'appli (en nous faisant donc perdre le focus) (ALT-TAB)
Procedure check_lostfocus()
 
  If IsScreenActive() = 0

      ReleaseMouse(1)
  
      ;Wait til our window is coming back to foreground - Attend que notre fenêtre repasse au premier plan
     Repeat
        ;now our events are to be processed with WaitWindowEvent, else IsScreenActive() will never say that our window has the focus again
        ;it should be written in the doc!
        ;maintenant les événements sont à gérer avec WaitWindowEvent, sinon IsScreenActive() ne dit jamais que notre fenêtre a à nouveau le focus
        ;il faudrait mettre ça dans la doc!!!!
        WaitWindowEvent()   
     Until IsScreenActive() <> 0

      ReleaseMouse(0)
     ;--- Optional
      ;Better recreate the screen - il vaut mieux recréer l'écran
      CloseScreen()
      init_display()
      ;and the sprites too (have to!) - et les sprites aussi (indispensable)
      create_sprites()
      ;give to the system some time to rest - laisse un peu le temps au système de récupérer
      Delay(2000)
     ;---

  EndIf

EndProcedure
It's not that hard...