News:

PlayBASIC2DLL V0.99 Revision I Commercial Edition released! - Convert PlayBASIC programs to super fast Machine Code. 

Main Menu

Any ideas? (Double Buffering Problems)

Started by Chas, December 08, 2005, 04:53:13 PM

Previous topic - Next topic

Chas

Hi,
I've just started PB and I wanted to slowly fill up the screen with circles
But when I try it:
1] the previous circles have moved position.
2] the screen background seems to alternate between dark black and dark blue  on each turn of the loop.


  sw=GetScreenWidth()
  sh=GetScreenHeight()
  Ink RGB(255,255,255)

  For n =0 To 10
         Circle Rnd(sw),Rnd(sh),50,0   
     Wait 1000
     Sync
  Next n
 
  WaitKey

I think that I've got completely the wrong idea ,could someone point me in the right direction?

BlinkOk


stef

Hi!

Yes, it's working absolutely normal.
the only colorchange is at start (message with compile etc) ,that's also normal



Greetings
stef

kevin

#3
Chas,

Ahh,  I assume your running this code in Full Screen mode ?.. Which is causing this age old logic error.  Welcome to the annoying world of computer graphics.. :)


The Screen is double buffered. Which means that unlike an Image say, there are in fact two copies of the screen in memory.  
Ok, so in full screen mode we have 2 copies of the screen.

The Front Buffer (the version we see)

The Back Buffer (the hidden version drawing operations actually take place on)  

 Both copies are complete separate from each other

This is require in virtually all computer graphics situations. Without it, the screen with flicker dramatically.  You might have seen this in old 8bit games. Were double buffering was often less practical.  Ie. C64 sprite multi plexers for notorious for this.


But  Full Screen and Window run a little differently, in Full Screen mode, the  double buffered screen actually swaps the two buffers, while windowed mode it doesn't.   So if you run your code in windowed mode it'll run as you expect, but it won't in full screen mode..

So in full Screen mode, since your program has not cleared the screen at all, it will start with the 2 internal copies of the screen, in two different states. Each sync there after, it will indeed swap between the 2 different versions of the screen image. So the image will cycle between the two..  Which is obviously not what we want.




Anyway, when we draw to the 'screen' we can only ever draw to the back buffer.   So Each time we sync, these two buffer are swapped.  So the buffer that was back buffer (we we were drawing to), becomes the front buffer (so we see what we rendered) and vice versa.

If you think about it logically for a second.   If you draw a circle to screen (which will be drawn to the back buffer),  then sync.  This will show us the drawn circle.  Now, if you draw another circle to the screen in different position and the sync again.  We'll see the second circle but not the first.   Since the first circle was drawn to other screen buffer.

ie..  check this out.


PlayBASIC Code: [Select]
Openscreen 800,600,32,2

Print "Screen Buffer #1"
Circle 100,100,50,1

Sync
waitkey
waitnokey

SetCursor 0,0
Print "Screen Buffer #2"
Circle 200,200,100,1

Sync
waitkey
waitnokey



; loop constantly flicking between the 2 copies of the screen.

Do
Sync
waitkey
waitnokey
loop








Now for your example, since your stock piling circles, and these circle are being drawn not to one copy of the screebn, but there being spread between the two copies of the screen..   So to counter the buffering we have to think logically.

The solution means that we have to draw each circle twice.  So it's drawn to both copies of the screen.  This will make the illusion seamless.

Here's how i'd do it.




Your Example..

PlayBASIC Code: [Select]
; Force the Screen to 800*600,32bit, if it's no already in full screen mode
if GetScreenType()<>2
Openscreen 800,600,32,2
endif

; clear Both copies of the screen upon start up
Cls 0: Sync
Cls 0: Sync


sw=GetScreenWidth()
sh=GetScreenHeight()
Ink RGB(255,255,255)


; limit the Sync rate so it's slow enough for us see whats happening
Setfps 10

For n =0 To 100

X=rnd(sw)
Y=rnd(sh)
; Draw this new circle to the current Back Buffer of the screen
Circle x,y,50,0

; swap the Back buffer for the the front buffer
Sync

; draw this last circle again, so appear on Both copies of screen buffer
Circle x,y,50,0

Next n

print "done"
Sync
WaitKey





Chas

Kevin,
Thank you for the very clear explanation, I do understand it now :)

-Is this 'full-screen swapping' really usefull, later on?
I was wondering if a 'setmodesimple' command, to force the screens to be copied to each other, would make life easier for children and beginners like me?
Thanks again
Chas

kevin

#5
Well ,without double buffering you can't really have moving computer graphics.  As the moving images would flicker like stop lights (this occurs because you can't manipulate the visible image while the monitor is drawing it.) . Not a nice effect.  This is not a PB thing, is a computer thing.  

 While I could triple buffer full screen mode, there are two main disadvantages.  This triples the size of the screen in memory, and adds substantial overhead to the syncing process.   Although on modern pc's that's debatable I guess.

Generally though when your game loop updates the screen,  it's going to be redrawing the entire screen each update, which makes such logic problems redundant.  As it only occurs when in situations like the one you've posted above.

You can simulate triple buffering you if you like.   To do so, just create a screen sized image, then redirect rendering to this image.  Once your done, Draw that image to the screen.   Then do it all again.


PlayBASIC Code: [Select]
 sw=GetScreenWidth()
sh=GetScreenHeight()
Ink RGB(255,255,255)


; create a screen sized image to act as our fake screen
CreateImage 1,sw,sh



For n =0 To 10
;redirect all rendering to the screen sized image
rendertoimage 1

; dra wyour circles onto this image
Circle Rnd(sw),Rnd(sh),50,0
Wait 1000


; redirect all rendering to the screen
RenderToScreen
; draw the screen sized image to the screen backbuffer
DrawImage 1,0,0,0

; show the current buffer
Sync
Next n

WaitKey








Chas

Hmm, I think that I will stick to windowed-mode, for a bit.
[Though your explanation & examples do make the job a lot clearer]

Is there a way to program the size of the 'window' to make it automatically match the display settings?