Page 1 of 1

Confusion about WindowEvent and FlipBuffers

Posted: Mon Oct 07, 2024 9:46 am
by PurePilish
Hello, all. I'm a new user of PB on Windows (only 1 or 2 weeks), but an experienced programmer. The program below is a toy version of something I've been working on. The FOR loop simulates the fact that my real program will have a need, every so often, to draw graphics that will take some time, say several seconds or even tens of seconds. The first version of this code did not contain either LINE A or LINE B, and it works fine. But while the drawing is being drawn the cursor turns into a spinning circle, suggesting that the For loop doesn't "yield" to Windows. Not surprising. To try and fix that I put in LINE A and that solved that problem, but the result is that the graphic doesn't appear - the window is just black. After several hours of trying things I put in LINE B on a whim, and voila, the graphics are there again. Trying all 4 combinations of LINE A and LINE B, the result is that LINE A and LINE B have to either both be used, or both be not used, in order to have the graphics show up at the end. I'm confused. Is this the expected behavior? It seems odd that WindowEvent and FlipBuffers are interrelated in this way. Since I really want LINE A (by processing the event I can allow the user to quit while it's drawing, for one thing) it seems I have to have LINE B also. Is there a different/better way to "yield" when drawing something that takes several seconds?

Code: Select all

#xres = 800:  #yres = 600

InitSprite()
OpenWindow(0, 0, 0, #xres, #yres, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, #xres, #yres)
LoadFont(0, "Verdana", 14) 
StartDrawing(ScreenOutput())
DrawingFont(FontID(0))
t = ElapsedMilliseconds()

For i=1 To 2000000
  event = WindowEvent()   ; ====== LINE A ======
  
  x = Random(#xres-1)
  y = Random(#yres-1)
  color = Random($ffffff)
  Plot(x, y, color)
Next

DrawText(5, 5, Str(ElapsedMilliseconds() - t), RGB(255, 255, 255))
StopDrawing()
FlipBuffers()   ; ====== LINE B ======
  
Repeat
  event = WindowEvent()    
Until event = #PB_Event_CloseWindow

Re: Confusion about WindowEvent and FlipBuffers

Posted: Mon Oct 07, 2024 1:49 pm
by miso
Hello, PurePilish, it's always good to see new users.
Don't be mad at me though, but I see multiple problems with that type of code.
To be constructive, I focus only to the question, and keep the rights to be proved wrong.

Line A needed to give some breath to the OS to do it's job (though best would be to iterate trough all). I guess, calling it sets the drawing frontbuffer to the invisible backbuffer when using a windowed screen, and that's why you need to call flipbuffers once to switch it back, and see the drawing.
So both A and B are needed.

The elegant (and advanced) way to do truely long drawings is to do it in a different thread.

Keep it up, and have a nice day. ;)

Re: Confusion about WindowEvent and FlipBuffers

Posted: Mon Oct 07, 2024 8:28 pm
by infratec
Yes, that's the way a flicker free 2d program works.

You draw something in a buffer and show it.
then you draw the next screen into a hidden buffer and then you use FipBuffers() to switch them in a pause, that you will not recognize
any flicker.

In earlier days you wait on the vertical backtrace to do this.

But this has nothing todo with PB, that's the way buffered drawing is working.

So I think your method is wrong.

You can create 2 Sprites and change the sprite which should be displayed.

Maybe this gives you an idea:

Code: Select all

#xres = 800:  #yres = 600

LoadFont(0, "Verdana", 14)

InitSprite()

OpenWindow(0, 0, 0, #xres, #yres, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, #xres, #yres)

CreateSprite(0, #xres, #yres)
CreateSprite(1, #xres, #yres)

If StartDrawing(SpriteOutput(0))
  DrawingFont(FontID(0))
  t = ElapsedMilliseconds()
  
  For i=1 To 2000000
    ;event = WindowEvent()   ; ====== LINE A ======
    
    x = Random(#xres-1)
    y = Random(#yres-1)
    color = Random($ffffff)
    Plot(x, y, color)
  Next
  
  DrawText(5, 5, Str(ElapsedMilliseconds() - t), RGB(255, 255, 255))
  StopDrawing()
EndIf

If StartDrawing(SpriteOutput(1))
  DrawingFont(FontID(0))
  t = ElapsedMilliseconds()
  
  For i=1 To 2000000
    ;event = WindowEvent()   ; ====== LINE A ======
    
    x = Random(#xres-1)
    y = Random(#yres-1)
    color = Random($ffffff)
    Plot(x, y, color)
  Next
  
  DrawText(5, 5, Str(ElapsedMilliseconds() - t), RGB(255, 255, 255))
  StopDrawing()
EndIf

SpriteNo = 0
DisplaySprite(SpriteNo, 0, 0)

AddWindowTimer(0, 0, 3000)

Repeat
  Repeat
      Event = WindowEvent()
      Select Event
        Case #PB_Event_Timer
          If EventTimer() = 0
            Debug "Change Sprite"
            SpriteNo + 1
            If SpriteNo = 2
              SpriteNo = 0
            EndIf
          EndIf
        Case #PB_Event_CloseWindow
          Exit = #True
      EndSelect
    Until Event = 0
  
    FlipBuffers()
    ClearScreen(0)
    DisplaySprite(SpriteNo, 0, 0)
Until Exit
Maybe screen is the wrong way for you.
If you have no 'realtime' changes, why not use simply a CanvasGadget and draw different images on it?

Re: Confusion about WindowEvent and FlipBuffers

Posted: Mon Oct 07, 2024 9:15 pm
by PurePilish
miso/infratec - Thank you for the replies, they are helpful. I understand how double buffering works, but it is still unexpected that checking for events changes whether a FlipBuffers() is required. Perhaps it is because I'm checking for events inside a StartDrawing / StopDrawing block? Anyway, I will consider switching to a canvas, and also learning about threads. Thanks again.

Re: Confusion about WindowEvent and FlipBuffers

Posted: Mon Oct 07, 2024 10:11 pm
by miso
but it is still unexpected that checking for events changes whether a FlipBuffers() is required.
Yes, it is.
For me, strange that you need no flipbuffers, when your first eventhandler call is after the drawing.
I guess, the first call sets the drawbuffer to the invisible one.

Iterating trough all the events do even more, it is required for normal mouse behavior, and also flipbuffers do more, than just switching
the front and backbuffer. (If I remember well, joystick handling in fullscreen mode is related to flipbuffers for example.)

Not knowing your exact plan for the program, I belive following infratec's advice (to try canvasgadget) should be the best for you.