smooth animation in a window - not possible?

Advanced game related topics
mp303

smooth animation in a window - not possible?

Post by mp303 »

Is it impossible to get completely smooth animation in a window, or am I doing something wrong?

Below is an example...

On line 1, you can switch between windowed mode or full screen by setting windowed.l to 0 (full screen) or 1 (windowed).

In full screen mode, the animation is completely smooth. But in windowed mode, there's a small "jump" in the animation every second or so.

Why?

Isn't FlipBuffers supposed to wait for vertical refresh? It seems it sometimes doesn't, or perhaps it waits too long... (I can't tell if it's skipping a frame or painting a frame too late)

My monitor is running at 60 FPS, and my system has loads of CPU power and plenty of RAM to go around... I've tried on three different systems, and this frame skipping/doubling occurs on all of them...

Any ideas?

thanks! :)

(code below...)

Code: Select all

windowed.l = 1

width.l = 512
height.l = 288

boxw.l = 30
boxh.l = 30

maxx.l = width - boxw
maxy.l = height - boxh

If InitSprite() = 0
  MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
  End
EndIf

If Windowed
  If OpenWindow(0, 0, 0, width, height, "A screen in a window...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    If Not OpenWindowedScreen(WindowID(0), 0, 0, width, height, 0, 0, 0)
      MessageRequester("Error", "Can't open windowed screen!", 0)
      End
    EndIf
  EndIf
Else
  SetRefreshRate(60)
  If Not OpenScreen(640,480,32,"Screen")
    MessageRequester("Error", "Can't open screen!", 0)
    End
  EndIf
EndIf


If Not InitKeyboard()
  MessageRequester("Error", "Can't init keyboard!", 0)
  End
EndIf

CreateSprite(0, 30, 30)
If StartDrawing(SpriteOutput(0))
  Box(0, 0, 30, 30, RGB(255, 0, 0))
  Box(5, 5, 20, 20, RGB(0, 255, 0))
  Box(10, 10, 10, 10, RGB(0, 0, 255))
  StopDrawing()
EndIf

If Not windowed : SetFrameRate(60) : EndIf

dx.f = 2
dy.f = 1

Repeat

  FlipBuffers(1) 
  
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape) : End : EndIf
  
  If windowed
  Repeat
    Event = WindowEvent()
    Select Event 
      Case #PB_Event_CloseWindow
        End 
    EndSelect
  Until Event = 0
  EndIf

  ClearScreen(RGB(0, 0, 0))

  x = x + dx
  y = y + dy
  
  If x > maxx : x = maxx : dx = -dx : EndIf
  If x < 0 : x = 0 : dx = -dx : EndIf
  
  If y > maxy : y = maxy : dy = -dy : EndIf
  If y < 0 : y = 0 : dy = -dy : EndIf

  DisplaySprite(0, x, y)
  
ForEver
[/code]
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8452
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

The trick is to set a high framerate and counterbalance it with a delay in the display loop. However, you can't finetune the timing closely enough with the default Windows timing resolution. You have to set it up higher while the screen is active and set it back when you're done. This (windowed only) version is moving perfectly smooth here:

Code: Select all

ExamineDesktops()
framerate = DesktopFrequency(0) * 3 ; *** change *** // Choose a nice high framerate
              
maxx.l = 482
maxy.l = 258

If InitSprite() = 0 Or InitKeyboard() = 0
  MessageRequester("Error", "Can't open screen & sprite enviroment!", 0) 
  End 
EndIf 


If OpenWindow(0, 0, 0, 512, 288, "A screen in a window...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  If Not OpenWindowedScreen(WindowID(0), 0, 0, 512, 288, 0, 0, 0) 
    MessageRequester("Error", "Can't open windowed screen!", 0) 
    End 
  Else 
    SetFrameRate(framerate) ; *** change  *** // Set framerate up 
  EndIf 
EndIf 

CreateSprite(0, 30, 30) 
If StartDrawing(SpriteOutput(0)) 
  Box(0, 0, 30, 30, RGB(255, 0, 0)) 
  Box(5, 5, 20, 20, RGB(0, 255, 0)) 
  Box(10, 10, 10, 10, RGB(0, 0, 255)) 
  StopDrawing() 
EndIf 

dx = 2 : dy = 1 

timeGetDevCaps_(@tc.TIMECAPS, SizeOf(TIMECAPS)) 
res = tc\wPeriodMin 

timeBeginPeriod_(res) ; *** change  *** // Raise timer resolution for added Delay()
                      ;                 // (counterbalances the high framerate) 

Repeat 

  FlipBuffers(1) 
  
  ExamineKeyboard() 
  If KeyboardPushed(#PB_Key_Escape) : End : EndIf 
  
  If WindowEvent() = #WM_CLOSE:End:EndIf
  
  Delay(11) ; *** change  *** // Add a finetuned Delay() to counter high framerate
  
  ClearScreen(#Black) 

  x = x + dx 
  y = y + dy 
  
  If x > maxx : x = maxx : dx = -dx : EndIf 
  If x < 0 : x = 0 : dx = -dx : EndIf 
  
  If y > maxy : y = maxy : dy = -dy : EndIf 
  If y < 0 : y = 0 : dy = -dy : EndIf 

  DisplaySprite(0, x, y) 
  
ForEver 

timeEndPeriod_(res) ; *** change  *** // Reset timer res to normal
Another advantage to this method is the low cpu usage provided by the Delay(). It's only using 3% here, compared to 100% with your code.
BERESHEIT
mp303

Post by mp303 »

thanks, that's perfectly smooth! and without blocking while waiting, that's a big bonus.

kinda makes you wonder why the standard functions don't implement it this way? seems like the proper way to implement it...
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

because it's a standard implementation,
wich means it has all the disadvantages of the original DX7 solution...
oh... and have a nice day.
mp303

Post by mp303 »

uh. and using 50% CPU to get half-descent synchronization is supposed to somehow be better?

I don't get it...
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

PB does nothing else than the standard solution of DX7 does.
PB is just calling DX7 functionallities.

the effect you complained about would occur in any program that uses standard DX7 functionalities,
no matter if it was written in C++, Delphi or whatever.
oh... and have a nice day.
mp303

Post by mp303 »

yeah, "everybody else does it".

right on.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

HELLO
is there anybody in there?

it is just a CALL of functions of the grafic subsystem!

the problem is caused by DirectX7, not by PureBasic!
oh... and have a nice day.
mp303

Post by mp303 »

Maybe I'm not making myself clear.

OpenWindowedScreen(), SetFrameRate(), FlipBuffers() ... are these not PB commands?

What I'm asking you is, why do these commands not implement it the way you just showed me in your example?

I know it may not be the "standard" way to implement it, but the "standard" way is obviously not very good, so why force every PB programmer to implement this workaround in every application over and over again?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

you made yourself perfectly clear, you just don't get the point.

I will explain it once again....

OpenWindowedScreen(), SetFrameRate(), FlipBuffers()
are PB commands that use functionallities of the Graphical Subsystem DirectX.

the example you saw is a WORKAROUND that uses a lot of additional functionallities to work this way.

netmaestro changes the timer resolution and applicates a very precisely precalculated Delay to make it work that way.
that is nothing connected with the graphical subsystem in any way,
that is something that is connected with the handling of the process.

sure an interface for the graphical subsystem should not mess with the process-timing, shouldn't it?

there is no way to implement a FlipBuffers that way, because it's not a Buffer issue but a process-timing issue.

...I hope that finally made it clear...
oh... and have a nice day.
mp303

Post by mp303 »

The manual states, "Waiting for the screen synchronization allows the flip to be perfect (no 'tearing' or other visible artifacts) because the flip is performed when the screen has been fully drawed".

Having read the manual, I was expecting FlipBuffers() to do a properly synchronized flip without further intervention on my part.

I would expect FlipBuffers() to do whatever it has to do to ensure that it functions.

If that means changing process timing, or some other technical workaround that most people probably wouldn't even understand, so be it.

If for some reason a few users need to tinker with process timing themselves, of course it might be nice if the command had a parameter to bypass this functionality.

But for the average user, I think this is what you would expect - a properly timed flip, without having to do a bunch of platform-specific workarounds to get it up and running.

I didn't need a workaround in AMOS or Blitz Basic on my Amiga in the 90s - I guess I expected things that were possible 15 years ago to be possible still today...

I guess it's a matter of difference in what people expect.[/i]
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

well, feel free to go to Silicon Vallay and kick Billies Ass for what sideeffects his so called OperatingSystem has.

a Screen and a Window are two completely different surfaces,
and it causes problems when you want to mix them both up,
that's just reality.

flipbuffers will flip "perfectly" in that way, that it is syncronized to avoid flipping buffers
in the middle of the disply-process of the monitor, which would lead to half-picture display.

you seem to have not the merest idea what the differences of an Amiga and a PC are.
go ahead and program PB on an Amiga, it's avaliable, don't you know?

if you want some special bypass timer-handling within a former simple flipbuffers,
go ahead, construct it, program it, write the code it would need.

perhaps after a long period of going into that materia you will see how it can work
and maybe you'll find some functionable solution,
but I rather expect you to learn that it's not worth sweating about the task to get it universal functional.

I wanted to explain to you, why anything is the way it is.
if you don't get it, I just stop bothering with you right here.
I have better ways to waste my time than explaning obvious things to someone who won't listen.


> I guess it's a matter of difference in what people expect.

sure I could expect Windows to be a super-duper Operating-System,
but to fill my needs I better should buy a UNIX-workstation.

If I can't efford a real computer, I have to cope with what I can afford.
oh... and have a nice day.
mp303

Post by mp303 »

heh, it seems I always manage to brush someone the wrong way here, whenever I point out anything that doesn't work.

anyway, what you're saying, basically, is that Windows is a crummy operating system, and therefore you should not expect anything to work correctly on it.

(at least not without quirky workarounds)

is that about it? :)
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

mp303 wrote:heh, it seems I always manage to brush someone the wrong way here, whenever I point out anything that doesn't work.
Probably because of the way that you point it out. :P

Come on, 'fess up. You enjoy stirring it don't you. :wink:
Dare2 cut down to size
mp303

Post by mp303 »

Dare wrote:Probably because of the way that you point it out. :P
read through the thread - I tried to play nice from the start, didn't I? :)

if you notice, my smart-ass remarks usually start around the time somebody gives me an explanation like "PB does nothing else than the standard solution of DX7 does". Gee, well, maybe it should? Maybe the standard solution isn't good enough?

I don't do anything "half" - a vertical sync that sometimes synchronizes, or sometimes drops a frame, is not good enough ... it's half-done, and I don't care if half-done is the "standard" for Windows or DirectX or the universe in general - if it can be done better, it should be.

I'm pretty uncompromising that way - I don't cut corners or accept "sort of" solutions to problems that I know can be solved properly, and I get terribly frustrated with people who try to convince me that less than perfect is "normal".

If it's worth doing, it's worth doing it right.
Post Reply