Same speed on all PCs - FPS independent!

Share your advanced PureBasic knowledge/code with the community.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Same speed on all PCs - FPS independent!

Post by BackupUser »

Code updated for 5.20+

Restored from previous forum. Originally posted by MrVainSCL.

Hi @ all
I found a small example how to run your program on all PCs in same speed but FPS independent... So i coded this small example... Btw i am not really happy with this result, because its not really smooth on my system ;(( But mabye this will help you...

Code: Select all

;-----------------------------------
;
; Run your prog in same speed on all 
; PCs but FPS independent - Example
;
;-----------------------------------
;
    #scrw = 640               ; screenwidth
    #scrh = 480               ; screendheight
    #scrd = 16                ; screendepth
;
;-------- Init all the needed system stuff --------
;
    If InitSprite() = 0 Or InitKeyboard() = 0
        MessageBox_ (0,"Can't open DirectX 7 or later", "ExampleSource", #MB_ICONINFORMATION|#MB_OK)
        End
    EndIf
;
;-------- Init Screen and load stuff --------
;
    If OpenScreen(#scrw,#scrh,#scrd,"ExampleSource") = 0                             
        MessageBox_ (0,"Could not open 640x480x16 screen", "ExampleSource", #MB_ICONINFORMATION|#MB_OK) 
        End                                                                                   
    EndIf
    ;
    SetPriorityClass_(GetCurrentProcess_(), 13 )           ; 13 = HIGH_PRIORITY_CLASS 
;  
;-------------------------------
;
    yspeed.f = 0.2
    oldmillisecs = GetTickCount_()
;
;-------- Test MainLoop --------
;
    Repeat    
        deltatime    = GetTickCount_() -oldmillisecs      ; Maybe use CurrentTime !? Mhhh...
        oldmillisecs = GetTickCount_()   
        ;
        ClearScreen(RGB(0,0,0))                           ; ClearScreen black
        ;       
        y = y+deltatime*yspeed                            ; this is movement by time elapsed.
        ;
        If y>480 : y=0 : EndIf
        ;
        StartDrawing(ScreenOutput())
           FrontColor(RGB(255,255,255))
           Box(320,y,16,16)  
        StopDrawing()
        ;     
        FlipBuffers()            
        ;              ;   
        ExamineKeyboard()            
   Until KeyboardPushed(#PB_Key_Escape) 
   
End

;-------------------------------
PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by chr1sb.

the resolution of the system clock that GetTickCount_() gets it's time from is not neccesarily 1 millisecond (it varies on different versions of Windows).

In winmm.dll there is timeBeginPeriod() and timeEndPeriod() functions:
timeBeginPeriod(1) to set the timer resolution to 1 ms
timeEndPeriod(1) to reset timer resolution to default value

not sure how to implement the above in PureBasic but maybe it explains your problem with not really smooth movement...
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.

Hi chr1sb
Many thanks for the tip... last days i found out that there are a lot developers on the net with big timing problems too(esp. between win98 and win2k)! I am not sure how correct does the "TimeGetTime()" and "QueryPerformanceCounter()" will work and how to use it correctly! :wink:

If someone know and could send me an working example, using "timeBeginPeriod()" and "timeEndPeriod()", please tell me as fast as possible :wink: Thanks!

PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by chr1sb.

I tried timeBeginPeriod_() and timeEndPeriod_() but it only seems to effect TimeGetTime_() and not GetTickCount_(). Here is my code for testing:

Code: Select all

If InitSprite() = 0 Or InitKeyboard() = 0

   MessageRequester("Error", "Can't open DirectX 7 Or later", 0)
  End

EndIf

If OpenScreen(800, 600, 16,"Test")

timeBeginPeriod_(1)

y=0

TheTime = TimeGetTime_() 

   Repeat

    FlipBuffers()
    OldTime = TheTime
    TheTime = TimeGetTime_() 
    
    StartDrawing(ScreenOutput())
    Locate(10,y)
     DrawText(Str(theTime-oldtime)) 
   
    StopDrawing()
    y+20
    If y>460
    y=0
    EndIf
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Escape)
  
timeEndPeriod_(1) 

Else
 MessageRequester("Error", "Can't open a 800*600 - 16 bit screen !", 0)
EndIf

End   
(excuse the flickering effect, but this code is just to see the result for elapsed time and not to look nice)

The results I get are 13 and 14 which is what I'd expect because my monitor is refreshing at 75Hz so the actual time elapsed is 13.33333etc milliseconds

Without using timeBeginPeriod_(1) the results are 10 and 20. Much less accurate

BTW I'm using Windows XP so you might not see the same result under Win98

The much more accurate hardware performance timer used by QueryPerformanceCounter() is not present on all PC's (especially older ones) so you can't rely on it if you want to run your program on different machines
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by fred.


Quick code to have a always a regular frame rate. If the FrameRate and the Screen refresh aren't the same, then slowdown and jerks are not avoidables..

Code: Select all


FrameRate = 60

If InitSprite() And InitKeyboard()

  SetRefreshRate(FrameRate) ; Try to open a 60fps, ultra smooth screen
  If OpenScreen(640, 480, 16, "Test") = 0 ; If it fails, probably the 60hz mode isn't valid (NT/2000/XP problem)
    SetRefreshRate(0)

    If OpenScreen(640, 480, 16, "Test") ; Try again, and let the OS choose the refresh rate for us
      SetFrameRate(FrameRate)  
    Else
      MessageRequester("Can't open screen", "", 0)
      End
    EndIf
  EndIf

  ; At this point we have screen opened
  ;

  Repeat
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Escape)

EndIf

Fred - AlphaSND
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Franco.

SetRefreshRate() is not documented yet.
Is it the same as SetFrameRate()

BTW: How can it be done to display the refresh rate on the screen


Have a nice day...
Franco

Sometimes you have to go a lonely way to accomplish genius things.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Motu.

well Fred, I just tried this.
Win 98SE
DirectX 8.1
600 Intel Celeron
Nvida Geforce 2

With:
SetRefreshRate(60)
SetRefreshRate(85)
SetRefreshRate(100)
SetRefreshRate(120)
and then
OpenScreen(800, 600, 16, "Test") always return zero...
But I know my Computer can do this. If I set the RefreshRate per Hand, it will work in the Program with all the four values.
Whats wrong ? Bug ?





Motu
-----------------
Martin Jässing
master creating (R)
[url]mailto:mjaessing@master-creating.com">mjaessing@master-creating.com
<a href="http://www.master-creating.com[/url]
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.
chr1sb wrote:
...the resolution of the system clock that GetTickCount_() gets it's time from is not neccesarily 1 millisecond (it varies on different versions of Windows)...
Hi!
I have tried your tip with "timeBeginPeriod()", "timeEndPeriod()" and "TimeGetTime()" comamnd in my example i have posted... Seems it works a bit more smooth but not really smooth enough to use it on my system

Btw is it correct that "timeEndPeriod_(1)" is outside the innerlopp? Mhhh... Have someone an idea how to get a very exactly time on every system for really smooth scrolling? Maybe own InlineAsm procedure?

Fred, could you add a really correct working timer command for game developers...? So game coders dont need to limit there fps... they still need only my posted source and if the timer works correct and fine too... the problem has been solved for all game coders!? :wink:



PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by chr1sb.
is it correct that "timeEndPeriod_(1)" is outside the innerlopp?
Yes, you only need timeBeginPeriod_(1) once and then timeEndPeriod_(1) when you're finished to set timer resolution back to default value. (so you probably don't need timeEndPeriod_(1) at all but it's polite for your program to put things back to how they were)

Whilst searching for more info about QueryPerformanceCounter() I found the following article which, although written about CDX library in C++, is the best explanation of this subject I have seen:

http://mirzaking.freeservers.com/CDXpaper.htm

Sadly for us the article linked above advises that dynamic framerates is not a good solution for 2D graphics...
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Danilo.

MrVain:
You got my Timer-Library and you got an example
how you can use it with plain WinAPI.
You should read some DOCs like MSDN about it,
otherwise you cant use it. Its that simple.

When you set a Timer to 50 FPS (20 milliseconds:
1000 / 50 = 20) and your code is too slow to run
within this time, your Timer cant run faster.

Its simple: Your code runs fine on a good PC
because that PC can execute more code in a given
time.
When you want the code to run on your very old system,
you should check and optimize your code or program it
directly in Assembly.

Another thing:
The timer-stuff is also _limited by windows_.
You cant change that.
Its better on newer systems like Win2k, but not
nice on very old OS´s like Win95/98...
Ask Billy Boy, maybe he will release a fix for
you and your old OS.

There is a reason why you should upgrade sometimes...
(hardware AND software)

cya,
...Danilo

(registered PureBasic user)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.

Hi @ all
Here is a fine working example how to code a game and run this on all PCs in the same speed but fps independent! At the moment i use TimeGetTime_ for this, because it returns better results as GetTickCount_ ! If PB will support 64 bit, i will post an example which works with more exactly timing results as TimeGetTime_ But this methode should be good enough for your game projects and for smooth scolling... Have a look to my small game where i used this methode too... Hope this source helps you... Bye...

Code: Select all

;-----------------------------------
;
; Run your prog in same speed on all 
; PCs but FPS independent - Example
;
; Works 100% fine on all PCs :wink:
;
;-----------------------------------
;
    #scrw = 640               ; screenwidth
    #scrh = 480               ; screendheight
    #scrd = 16                ; screendepth
;
;-------- Init all the needed system stuff --------
;
    If InitSprite() = 0 Or InitKeyboard() = 0
        MessageBox_ (0,"Can't open DirectX 7 or later", "WorkingExample", #MB_ICONINFORMATION|#MB_OK)
        End
    EndIf
;
;-------- Init Screen and load stuff --------
;
    If OpenScreen(#scrw,#scrh,#scrd,"ExampleSource") = 0                             
        MessageBox_ (0,"Could not open 640x480x16 screen", "WorkingExample", #MB_ICONINFORMATION|#MB_OK) 
        End                                                                                    
    EndIf
    ;
    SetPriorityClass_(GetCurrentProcess_(), 13 )                 ; 13 = HIGH_PRIORITY_CLASS, better for games! 
;  
;-------- Init Timer before innerloop --------
;
    oldmillisecs.f = TimeGetTime_()                              ; TimeGetTime_ return better results as GetTickCount_
;
;-------- Test MainLoop --------
;
    Repeat    
        deltatime.f    = TimeGetTime_() -oldmillisecs.f          ; Dont forget to use floats!
        oldmillisecs.f = TimeGetTime_()   
        ;
        ClearScreen(0,0,0)                                       ; ClearScreen black
        ;       
        yscroll.f = yscroll.f+deltatime.f*(480/2000)             ; this is movement by time elapsed.        
        If yscroll.f >= 480 : yscroll.f=yscroll.f-480 : EndIf
        ;
        StartDrawing(ScreenOutput())
           FrontColor(255,255,255)
           Box(320,yscroll,16,16)  
        StopDrawing()
        ;     
        FlipBuffers()            
        ;              ;   
        ExamineKeyboard()            
   Until KeyboardPushed(#PB_Key_Escape) 
   
End

;-------- How to understand the stuff --------
; 
; "yscroll.f" is our variable we would normaly use to move our object like "yscroll+1" or whatever but we dont have
; to use a fix variable like +1 for an independent fps! We have to calculate this variable (moving steps) :wink:
;
; We have to  calculate the steps using "yscroll.f = yscroll+deltatime.f*(480/2000)" for example... The only important
; things in this line are the vals 480 and 2000 for us... This means: We want to move an object on a way of 480 pixel
; (our screenhigh for example) and the object should move this way in only 2 seconds (also 2000 millisecs) ...
;
; If you want for example, that our object will need 4,5 seconds to move this 480 pixels - you have to write (480/4500)
; Thats all... I think this small example with documentation should be good enough and not to hard to understand for
; your next projects :wink:
;
; Good luck... "Mr.Vain of Secretly!" aka Thorsten




PIII450, 256MB Ram, 6GB HD, RivaTNT, DirectX8.1, SB AWE64, Win98SE + Updates...

greetz
MrVainSCL! aka Thorsten
Post Reply