Why is FlipBuffers() is not required?

Just starting out? Need help? Post your questions and find answers here.
swhite
Enthusiast
Enthusiast
Posts: 727
Joined: Thu May 21, 2009 6:56 pm

Why is FlipBuffers() is not required?

Post by swhite »

Hi

I have written some test code so I can learn about 2D drawing. In the case below I am simulating a person at a fuel station entering their PIN. I display asterisks in response to keystrokes. I have removed the keyboard for simplicity so I can just see what happens on the display. As you can see FlipBuffers() is required after I display the Welcome message but is not needed thereafter. I would like to understand why FlipBuffers() is not needed in the Repeat Loop.

I am running PB 5.72 on Linux OpenSuse 15.1. The attached display resolution is 800 x 480.

Code: Select all

;
; dCFusnFSC_Scn.pb - Commands to draw on the screen
;
#dCTestMode = 0
#dCScrnWidth           = 800
#dCScrnHeight          = 480
#dCScnForeColor        = $00FF00
#dCScnBackColor        = $000000
#dCScnFontName         = "DejaVu Sans Mono"
#dCScnFontSize         =  18
#dCScnNo = 5
#dCImageNo = 6
#ScnBottom = -1
#ScnTop = -2
#dCLogFile = "dcFusnFSC.log"

;XIncludeFile "dCSettings.pb"
;XIncludeFile "dC_Wait.pb"
;XIncludeFile "dC_CloseFile.pb"
;XIncludeFile "dC_Logging.pb"
Structure Scrn
   ID.i
   Font_Name.s
   Font_Size.a
   Font_B.a
   Font_I.a
   Font_U.a
   Font_ID.i
   Position_X.i
   Position_X1.i
   Position_Y.i
   Position_Y1.i
   Std_X.i
   Std_Y.i
EndStructure
Global goScn.scrn
Procedure Scn_LineA(*toScn.scrn,tnColor.i=0,tnY1.i=-1,tnX1.i=-1,tnWidth.i=-1,tnHeight.i=-1)
   If tnY1 = -1.0
      tnY1 = *toScn\Position_Y + *toScn\Std_Y
      tnX1 = 0
      tnWidth = #dCScrnWidth
      tnHeight = 1
   EndIf
   StartDrawing(WindowOutput(#dCScnNo))
   Line(tnX1,tnY1, tnWidth,tnHeight ,tnColor) 
   StopDrawing()
EndProcedure   
Procedure Scn_Write(*toScn.scrn,tnY.i=0,tnX.i=0,tcText.s="",tnForeColor.i=#dCScnForeColor,tnBackColor.i=#dCScnBackColor)
   *toScn\Position_X = *toScn\Std_X * tnX
   *toScn\Position_Y = *toScn\Std_Y * tnY
   StartDrawing(WindowOutput(#dCScnNo))
   DrawingFont(*toScn\Font_ID)
   DrawText(*toScn\Position_X,*toScn\Position_Y,tcText,tnForeColor,tnBackColor)
   *toScn\Position_X = *toScn\Position_X + TextWidth(tcText)
   StopDrawing()
EndProcedure
Procedure Scn_Append(*toScn.scrn,tcText.s,tnForeColor.i=#dCScnForeColor,tnBackColor.i=#dCScnBackColor)
   StartDrawing(WindowOutput(#dCScnNo))
   GrabDrawingImage(0,0,0,#dCScrnWidth,#dCScrnHeight)
   DrawingFont(*toScn\Font_ID)
   DrawImage(ImageID(0),0,0,#dCScrnWidth,#dCScrnHeight)
   DrawText(*toScn\Position_X,*toScn\Position_Y,tcText,tnForeColor,tnBackColor)
   *toScn\Position_X = *toScn\Position_X + TextWidth(tcText)
   StopDrawing()
EndProcedure
Procedure Scn_BSpace(*toScn.scrn)
   *toScn\Position_X = *toScn\Position_X - *toScn\Std_X
   StartDrawing(WindowOutput(#dCScnNo))
   GrabDrawingImage(0,0,0,#dCScrnWidth,#dCScrnHeight)
   DrawingFont(*toScn\Font_ID)
   DrawImage(ImageID(0),0,0,#dCScrnWidth,#dCScrnHeight)
   DrawText(*toScn\Position_X,*toScn\Position_Y," ",tnForeColor,tnBackColor)
   StopDrawing()
EndProcedure
Procedure Scn_WriteC(*toScn.scrn,tnY.i=0,tnX.i=0,tcText.s="",tnForeColor.i=#dCScnForeColor,tnBackColor.i=#dCScnBackColor)
   *toScn\Position_X = (#dCScrnWidth - TextWidth(tcText))/2
   *toScn\Position_Y = *toScn\Std_Y * tnY
   StartDrawing(WindowOutput(#dCScnNo))
   DrawingFont(*toScn\Font_ID)
   DrawText(*toScn\Position_X,*toScn\Position_Y,tcText,tnForeColor,tnBackColor)
   *toScn\Position_X = *toScn\Position_X + TextWidth(tcText)
   StopDrawing()
EndProcedure
Procedure Scn_WriteR(*toScn.scrn,tnY.i=0,tnX.i=0,tcText.s="",tnForeColor.i=#dCScnForeColor,tnBackColor.i=#dCScnBackColor)
   *toScn\Position_X = #dCScrnWidth - TextWidth(tcText)
   *toScn\Position_Y = *toScn\Std_Y * tnY
   StartDrawing(WindowOutput(#dCScnNo))
   DrawingFont(*toScn\Font_ID)
   DrawText(*toScn\Position_X,*toScn\Position_Y,tcText,tnForeColor,tnBackColor)
   *toScn\Position_X = #dCScrnWidth
   StopDrawing()
EndProcedure
Procedure Scn_Picture(*toScn.scrn,tcImg.s,tnY1.i,tnX1.i,tnScale_Y = 1.0,tnScale_X.d = 1.0)
   If LoadImage(#dCImageNo,tcImg)
      *toScn\Position_X = *toScn\Std_X * tnX1
      *toScn\Position_Y = *toScn\Std_Y * tnY1
      If tnScale_Y <> 1.0 Or tnScale_X <> 1.0
         ResizeImage(#dCImageNo,ImageWidth(#dCImageNo) * tnScale_X,ImageHeight(#dCImageNo) * tnScale_Y)
      EndIf
      StartDrawing(WindowOutput(#dCScnNo))
      DrawImage(ImageID(#dCImageNo),*toScn\Position_X,*toScn\Position_Y,ImageWidth(#dCImageNo),ImageHeight(#dCImageNo))
      *toScn\Position_X = *toScn\Position_X + ImageWidth(#dCImageNo)
      *toScn\Position_Y = *toScn\Position_Y + ImageHeight(#dCImageNo)
      StopDrawing()
   EndIf
EndProcedure   
Procedure Scn_PictureA(*toScn.scrn,tcImg.s,tnY1.i,tnX1.i,tnScale_Y = 1.0,tnScale_X.d = 1.0)
   If LoadImage(#dCImageNo,tcImg)
      If tnScale_Y <> 1.0 Or tnScale_X <> 1.0
         ResizeImage(#dCImageNo,ImageWidth(#dCImageNo) * tnScale_X,ImageHeight(#dCImageNo) * tnScale_Y)
      EndIf
      StartDrawing(WindowOutput(#dCScnNo))
      DrawImage(ImageID(#dCImageNo),tnX1,tnY1,ImageWidth(#dCImageNo),ImageHeight(#dCImageNo))
      *toScn\Position_X = tnX1 + ImageWidth(#dCImageNo)
      *toScn\Position_Y = tnY1 + ImageHeight(#dCImageNo)
      StopDrawing()
   EndIf
EndProcedure   
Procedure Scn_WriteA(*toScn.scrn,tnY.i=0,tnX.i=0,tcText.s="",tnForeColor.i=#dCScnForeColor,tnBackColor.i=#dCScnBackColor)
   *toScn\Position_X = tnX
   *toScn\Position_Y = tnY
   StartDrawing(WindowOutput(#dCScnNo))
   DrawText(*toScn\Position_X,*toScn\Position_Y,tcText,tnForeColor,tnBackColor)
   *toScn\Position_X = *toScn\Position_X + TextWidth(tcText)
   StopDrawing()
EndProcedure
Procedure.i Scn_GetPosition_X(*toScn.scrn)
   ProcedureReturn *toScn\Position_X
EndProcedure
Procedure.i Scn_GetPosition_Y(*toScn.scrn)
   ProcedureReturn *toScn\Position_Y
EndProcedure
Procedure.i Scn_GetStd_Y(*toScn.scrn)
   ProcedureReturn *toScn\Std_Y
EndProcedure  
Procedure Scn_IncPosition_Y(*toScn.scrn,tnInc.i)
   *toScn\Position_Y + tnInc
EndProcedure   
Procedure Scn_IncPosition_X(*toScn.scrn,tnInc.i)
   *toScn\Position_X + tnInc
EndProcedure  
Procedure Scn_PushPosition(*toScn.scrn)
   *toScn\Position_X1 = *toScn\Position_X
   *toScn\Position_Y1 = *toScn\Position_Y
EndProcedure
Procedure Scn_PopPosition(*toScn.scrn)
   *toScn\Position_X = *toScn\Position_X1
   *toScn\Position_Y = *toScn\Position_Y1
EndProcedure
Procedure.i Scn_GetTxt_Y(*toScn.scrn,tcText.s)
   ProcedureReturn TextHeight(tcText)
EndProcedure   
Procedure.i ScnGetTxt_X(*toScn.scrn,tcText.s)
   ProcedureReturn TextWidth(tcText)
EndProcedure  
Procedure.i Scn_Clear(*toScn.scrn)
   StartDrawing(WindowOutput(#dCScnNo))
   Box(0,0,#dCScrnWidth,#dCScrnHeight,#dCScnBackColor)
   StopDrawing()
   FlipBuffers()
   *toScn\Position_X = 0
   *toScn\Position_Y = 0
EndProcedure
Procedure Scn_SetFont(*toScn.scrn,tcFont.s=#dCScnFontName,tnSize.a=#dCScnFontSize,tlB.a=0,tlI.a=0,tlU.a=0)
   Define lnFlag.i
   If tcFont <> ""
      *toScn\Font_Name = tcFont
   EndIf
   *toScn\Font_Size = tnSize
   *toScn\Font_B = tlB
   *toScn\Font_I = tlI
   *toScn\Font_U = tlU
   If tlB
      lnFlag | #PB_Font_Bold
   EndIf
   If tlI
      lnFlag | #PB_Font_Italic
   EndIf
   If tlU
      lnFlag | #PB_Font_Underline
   EndIf
   *toScn\Font_ID = FontID(LoadFont(#PB_Any,*toScn\Font_Name,*toScn\Font_Size,lnFlag))
   If *toScn\Font_ID
      StartDrawing(WindowOutput(#dCScnNo))
      DrawingFont(*toScn\Font_ID)
      *toScn\Std_X = TextWidth("X")
      *toScn\Std_Y = TextHeight("X")
      StopDrawing()
   Else
;      WriteToLog("Screen Font "+*toScn\Font_Name+" "+Str(*toScn\Font_Size)+"pt did not load")
   EndIf
EndProcedure
Procedure.i Scn_Init(*toScn.scrn)
   If Not InitSprite()
;      WriteTolog("Scn_Init() - InitSprite failed")
   ElseIf Not OpenWindow(#dCScnNo,0,0,#dCScrnWidth,#dCScrnHeight,"MultiPass Lite",#PB_Window_TitleBar) 
;      WriteTolog("Scn_Init() - OpenWindow failed")
   ElseIf Not OpenWindowedScreen(WindowID(#dCScnNo),0,0,#dCScrnWidth,#dCScrnHeight)
;      WriteTolog("Scn_Init() - OpenWindowedScreen failed")
   Else
      Scn_SetFont(*toScn)
      Scn_Clear(*toScn)
      ProcedureReturn 1
   EndIf
   ProcedureReturn 0
EndProcedure

If Scn_Init(@goScn)
   Scn_Write(@goScn,1,1,"Welcome to KardTech Fuels")
   ;Scn_Picture(@goScn,"doc/CompanyLogo.bmp",3,0)
   FlipBuffers()                                                       ; Why is FlipBuffers() need here?
   Delay(5000)
   Scn_Clear(@goScn)
   Scn_Write(@goScn,1,0,"Enter PIN:")
   Scn_Append(@goScn,"1")
   lnSec=ElapsedMilliseconds()
   Repeat
      Scn_Append(@goScn,"*")                                 ;Why is FlipBuffers() not needed here?
      Delay(500)
   Until ElapsedMilliseconds() - lnSec > 5000

EndIf   

   
Simon White
dCipher Computing
User avatar
Derren
Enthusiast
Enthusiast
Posts: 313
Joined: Sat Jul 23, 2011 1:13 am
Location: Germany

Re: Why is FlipBuffers() is not required?

Post by Derren »

FlipBuffers is never necessary (as in: your programm won't function without it).
It just allows for complex drawing operations to be done in the background and then pushing the completed image to the screen.
If you draw a bunch of stuff on the screen and don't use flipbuffers, you can watch as the drawing happens (sprites appear one by one).
It might be a cool effect, but you probably want that "crisp" 60 (or whatever) frames per second, rather than 60 frames, where every frame takes another 0,3 frames to completely build.

If you don't find that FlipBuffers is needed, your drawing operations are not complex enough for your graphics card to handle in a single frame.
If you had a more complex scenery to draw, you would probably realize why it's necessary (as in: you want that function in order to create that crisp, flicker-free image)
swhite
Enthusiast
Enthusiast
Posts: 727
Joined: Thu May 21, 2009 6:56 pm

Re: Why is FlipBuffers() is not required?

Post by swhite »

Hi

This raises the question as to why the "Welcome to KardTech Fuels" message is never displayed unless I add the FlipBuffers().

Simon
Derren wrote:FlipBuffers is never necessary (as in: your programm won't function without it).
It just allows for complex drawing operations to be done in the background and then pushing the completed image to the screen.
If you draw a bunch of stuff on the screen and don't use flipbuffers, you can watch as the drawing happens (sprites appear one by one).
It might be a cool effect, but you probably want that "crisp" 60 (or whatever) frames per second, rather than 60 frames, where every frame takes another 0,3 frames to completely build.

If you don't find that FlipBuffers is needed, your drawing operations are not complex enough for your graphics card to handle in a single frame.
If you had a more complex scenery to draw, you would probably realize why it's necessary (as in: you want that function in order to create that crisp, flicker-free image)
Simon White
dCipher Computing
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Why is FlipBuffers() is not required?

Post by Olliv »

You output everything on the window...

No the better target : use ScreenOuput() instead of WindowOutput()...

And so after this modifying, flip the buffers.
User avatar
Derren
Enthusiast
Enthusiast
Posts: 313
Joined: Sat Jul 23, 2011 1:13 am
Location: Germany

Re: Why is FlipBuffers() is not required?

Post by Derren »

Then my info is not correct.
The helpfile says back and front are flipped.
Seems like you start out in the back and then with FlipBuffers() used once, your drawing is pushed to the screen.
If you do not alter it afterwards, FlipBuffers is no longer needed (only again, if you want to update the screen again)
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Why is FlipBuffers() is not required?

Post by Olliv »

This is very specific. We (the humankind in general) often says that the proudness can give blindness.

If I affirm I am right I will direct sWhite to a video system, which has conveniences, but is complex in coding.

So, I prefer say I am wrong !

To choose the right drawing support (screen, image, canvas), we must consider what is the final goal.

To be right, I must say :

1) to be speed
2) to use GPU Video ressources (but not CPU motherboard ressources)
3) to use mouse and keyboard simply but to draw less simply*
4) to be sure only have one simultaneous screen displayed
5) to be ready to include 100Kb of basic graphic library in the EXE,

in this way, use screen acceleration and all the screen statements which are required (openScreen/openWindowedScreen, ClearScreen, ScreenOutput, FlipBuffers, etc...)

If all these conditions are not reached, you have not to use Screen specifically. There are others ways : canvas and ogl if desktop mouse and desktop keyboard input devices are used.

If few keyboard commands are required, you can stay with window or images (ImageGadget, imageOutput).

Now, this allows us not to exclude several infos depending of the drawing support.




(*): to be rightly speed in screen, we use sprite as any dynamical images accessed through SpriteOutput.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Why is FlipBuffers() is not required?

Post by netmaestro »

Why bother opening a screen if you're not going to use it? You're drawing to WindowOutput with no event loop or callback so nothing is persistent and your window hogs the whole cpu. Look in the doc for examples under Sprite & Screen to see how you should be doing this because what you have is way wrong.
BERESHEIT
swhite
Enthusiast
Enthusiast
Posts: 727
Joined: Thu May 21, 2009 6:56 pm

Re: Why is FlipBuffers() is not required?

Post by swhite »

Hi

Yes I know all about event loops and I do use them. As I mentioned at the start this was some test code to learn how 2D/screen functions work not production code. When I first tested it I did have an event loop with WindowEvent() and ExamineKeyboard() etc. but I removed all of this because I noticed some behavior I could not explain. Namely that I only needed to use FlipBuffers() once but not after that and wanted to know why. That is still the question I need to answer. As you can see in the Repeat Loop I am not using Flipbuffers() but the display is updated. If DrawingText() is being done on the back buffer what is triggering it to become the front buffer?

Simon
Simon White
dCipher Computing
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1252
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Why is FlipBuffers() is not required?

Post by Paul »

swhite wrote:Hi
As you can see in the Repeat Loop I am not using Flipbuffers() but the display is updated. If DrawingText() is being done on the back buffer what is triggering it to become the front buffer?
Simon
As netmaestro has already told you... FlipBuffer is NOT needed because you are NOT drawing to a Screen, you are drawing to a Window (no Buffer to Flip).
When you draw to a Screen you are drawing on the Buffer which needs to be flipped into view when you are done drawing.
The drawing to Screen method is very fast because it uses hardware acceleration.

All of your code draws to the Window which does not require flipping into view. You can remove any instance of FlipBuffer from your code as well as OpenWindowedScreen because it is never used. You are drawing directly on your Window and not on your graphic Screen.


Drawing to Window (flipping is not required)...

Code: Select all

x=2

If OpenWindow(1,10,10,400,300,"Window")

  Repeat
    h+x
    If h>400:x=-2:EndIf
    If h<0:x+2:EndIf
    
    If StartDrawing(WindowOutput(1)) ;<-- Drawing directly to Window
      Box(0,0,400,300,0)
      Box(h,130,20,20,#Yellow)
      StopDrawing()
    EndIf

    Delay(10)
  Until WindowEvent()=#PB_Event_CloseWindow
EndIf

Drawing to Screen (Flip is required to draw Buffer to Screen, remove FlipBuffers and you will no longer see updates)...

Code: Select all

InitSprite()
x=2
  
If OpenWindow(1,10,10,400,300,"Screen")
  OpenWindowedScreen(WindowID(1),0,0,400,300)

  Repeat
    h+x
    If h>400:x=-2:EndIf
    If h<0:x+2:EndIf
    
    ClearScreen(0)
    If StartDrawing(ScreenOutput()) ;<-- Drawing to Screen
      Box(h,130,20,20,#Yellow)
      StopDrawing()
    EndIf

    FlipBuffers() ;<-- Must be flipped into view
    Delay(10)
  Until WindowEvent()=#PB_Event_CloseWindow
EndIf

Drawing to Screen but much faster by using pre-drawn Sprite instead of drawing Box each time...

Code: Select all

InitSprite()
x=2
  
If OpenWindow(1,10,10,400,300,"Screen")
  OpenWindowedScreen(WindowID(1),0,0,400,300)
  CreateSprite(2,20,20)
  If StartDrawing(SpriteOutput(2))
    Box(0,0,20,20,#Yellow)
    StopDrawing()
  EndIf
  
  Repeat
    h+x
    If h>400:x=-2:EndIf
    If h<0:x+2:EndIf
    
    ClearScreen(0)
    DisplaySprite(2,h,130)

    FlipBuffers()
    Delay(10)
  Until WindowEvent()=#PB_Event_CloseWindow
EndIf
Image Image
swhite
Enthusiast
Enthusiast
Posts: 727
Joined: Thu May 21, 2009 6:56 pm

Re: Why is FlipBuffers() is not required?

Post by swhite »

Hi

I originally started with ScreenOutput() but things did not work as expected so I thought I had made a mistake and should use WindowOutput() because the screen was contained in a Window. So now I see why people thought my code was crazy. Since I am not building games where speed is important I will just use drawing to the Window without using any screen.

Thanks
Simon
Simon White
dCipher Computing
User avatar
Demivec
Addict
Addict
Posts: 4091
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Why is FlipBuffers() is not required?

Post by Demivec »

It might make sense to use a CanvasGadget() instead so that your drawing would be persistent. Just move your window of screen or another window over the top of it to see what I mean.
swhite
Enthusiast
Enthusiast
Posts: 727
Joined: Thu May 21, 2009 6:56 pm

Re: Why is FlipBuffers() is not required?

Post by swhite »

Thanks for that suggestion.

Simon
Simon White
dCipher Computing
Post Reply