Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: Shockwave on May 13, 2006
-
I know you can wait for V-Sync with;
WAIT &H3DA, 8
And Tinypct handles double buffering for you but I've noticed that you don't get a rock steady refresh with either method.
It's not so noticeable for most things, except when you want to make a scroller and you can see that the refresh rate is definately not constant and you get tears in the display when refreshing the display.
Has anyone found a rock steady way to tie the refresh rate to a constant say 80fps without using any includes?
Perhaps an assembly language snippet to do this?
-
Try delta timing, when you use the fps of the current running speed of your program, divided by your actually monitor refresh rate, to give the difference in speed loss / gain. And * mutliply that to any angles / counters. That might sort you out.
I've yet to implement this method and test it, as I do find the same odd shinanigans with the fps. Even on a simple thing with a few dots on screen.
-
@Shockwave: Try that FPS Limiter (http://dbfinteractive.com/index.php?topic=75.0) merged with this one, I know that it uses windows.bi include, but I'm sure that your final executable won't be bloated.
I've just recoded to FB one smart routine by Alan Macdonald (Delta time).
'
'
' Sample test by Rbraz 2006
'
'
Option Explicit
'Windowed
#define PTC_WIN
'-------------------------------------
' Includes.
'-------------------------------------
#Include Once "tinyptc.bi"
'Keys const
Const KEY_ESC = 27
Dim Key$
'Sub Routines
Declare Sub FPS_Count()
Declare Function AdjustFloat( byval fltCurrent as double, byval fltDesired as double, byval fltStepSize as double ) as double
'Variables
Dim Shared fltMultiplier as double ' How much the effect speeds-up/slows-down in order
Dim Shared fltNewMultiplier as double = 1 ' to run at the same speed on all PC's...
Const MAX_FPS = 90.0 ' Max. frames per second allowed
'FPS Counter
Dim Shared iFPS, bSettime,iSecStart,iFrameCount,iFrameStart as integer
'TinyPTC Buffer
Dim Shared Buffer(640*480) as integer
'Open TinyPTC window
If( ptc_open( "Adjust Float", 640, 480 ) = 0 ) Then
End -1
End if
'Main Loop
While Key$ <> Chr$( KEY_ESC )
Key$=Inkey$()
FPS_Count()
Locate 1,1
Print "FPS: "; iFPS
Locate 3,1
Print "fltMultiplier: "; fltMultiplier
' Use FPS to calculate the delta time so that the
' effect will run at the same speed on all PC's.
'
If iFPS >= 1 Then
fltNewMultiplier = MAX_FPS / iFPS
fltMultiplier = AdjustFloat( fltMultiplier, fltNewMultiplier, 0.5 )
End If
Ptc_Update @Buffer(0)
Wend
'Close TinyPTC window
ptc_close()
Sub FPS_Count()
If bSettime = 1 then
iSecStart = Timer() * 1000
iFrameStart = iFrameCount
bSettime = 0
EndIf
If Timer() * 1000 >= iSecStart + 1000 then
iFPS = iFrameCount - iFrameStart
bSettime = 1
EndIf
iFrameCount = iFrameCount + 1
End Sub
'----------------------------------------------------------------------
' NAME : AdjustFloat() by Alan MacDonald
' PURPOSE : Changes a variable's current value by a given step size
' towards a desired value.
' INPUTS : fltCurrent - The variable's current value.
' fltDesired - The variable's desired value.
' fltStepSize - Increment/decrement amount.
' RETURNS : The adjusted variable's value.
'----------------------------------------------------------------------
Function AdjustFloat( byval fltCurrent as double, byval fltDesired as double, byval fltStepSize as double ) as double
'
' Does the current value need to be increased to meet the desired value ?
'
If fltCurrent < fltDesired Then
fltCurrent = fltCurrent + fltStepSize
If fltCurrent > fltDesired Then
fltCurrent = fltDesired
End If
End If
'
' Does the current value need to be decreased to meet the desired value ?
'
If fltCurrent > fltDesired Then
fltCurrent = fltCurrent - fltStepSize
If fltCurrent < fltDesired Then
fltCurrent = fltDesired
End If
End If
Return fltCurrent
End Function
-
Thanks Rbraz, I'll give that a bash and see if it smooths things out a bit.
-
That's a great thread! Our alltime problem. I have to research more into it and ask people too..
My recent demos use a timer for the movement, though I update instantly as fast as I can. What if I read the refresh rate of the current resolution, and timed the screen buffer refresh only at that framerate?
p.s. From the Blitzbasic demos I've recently watch, most cool onescreens with oldschool scrollers, I see there is no problem there and the scrolls are smooth like silk! Damn,. why isn't it the same in Freebasic or my SDL/TPTC projects in C? I have to research it if I ever find the time and ask some democoders at Pouet..
-
I also use Delta time, and nice snippet there Rbraz. You could do away with the need for including windows if you wanted.
Blitz Basic uses DirectX to render with. That mostly covers the Syncing issues.
With Freebasic I have a hunch it's to do with the headers and compatibility. Just a thought.
With gfxlib, there is a screen sync command, and I recon it's slightly better then tiny. Allthough, I am going to use tiny for a bit longer.
-
Clyde, there has to be a way around this problem, I think that Optimus is onto the right track because if you know the refresh rate of the monitor then it would be fairly simple to time the refresh to that speed.
I did the same thing with the dbf bbstro, I matched it to 85fps, however it backfired on me causing slowdown on some systems that should have been able to run it fast.
-
I mostly find slugigishness when using text routines mostly bitmap scrollers.
-
EDIT: I fixed a small typo that made a miniscule difference in the limiting code
I've got a couple snippets of code.. They work pretty well. Checks for vsync once, and holds to a given refresh rate.
There's still some snippets in the "tinyptclib.bi" file that are under construction =)
Hopefully, my efforts may help someone
In this file you have to change vsyncrate to your monitor's refresh rate
#Define PTC_WIN
#include "TinyPTCLib.bi"
#include "RAnd.bi"
SeedRnd timer
Graphics 640,480,"Test"
dim inky as string
dim mytime as double
dim ttime as double
dim timeval as double
dim ctime as double
dim diff as double
dim am as double
dim sttime as double
dim vsyncrate as double
dim blah as string
'Set vsync rate
vsyncrate = 75
timeval = (1000.0/vsyncrate)/1000.0
WAIT &h3da, 8
mytime = timer
sttime = timer
do
inky=inkey$
'WAIT &H3DA, 8
FlipSurf
ClsSurf
ColorSet rand(0,255),rand(0,255),rand(0,255)
dim x as integer
dim y as integer
dim i as integer
'for i=0 to rand(rand(1,15),rand(1,15))
for x=0 to GFXWID-1
for y=0 to GFXHT-1
plot(x,y)
next
next
'next
'buffer[5*GFXWID+5] = &hFFFFFF
ttime = timer-mytime
ctime = timer'ttime+mytime
if ttime < timeval then
diff = timeval-ttime
'print diff
do
loop until timer-ctime >= diff-(timeval/1000.0) or asc(inky) = 27
elseif ttime > timeval then
diff = ttime-timeval
'ctime = timer
am = ((cint(diff / timeval)+1)*timeval)-diff
do
loop until timer-ctime >= am or asc(inky) = 27
endif
ttime = timer-mytime
mytime = timer
print 1.0/ttime
'print (mytime-sttime)/timeval
loop until asc(inky) = 27
tinyptclib.bi
#Include "tinyptc.bi"
'TinyPTC Graphics Interface Lib
'Copyright Chris Gaiter 2006
'
'
'This Library takes the basic functionality of TinyPTC and allows more advanced
'drawing operations with simplified commands. Commands such as Graphics,
'FlipSurf, ClsSurf, Plot, ColorSet, DrawLine, and Oval (Not Yet implemented)
'
'
'
'Command reference is coming soon, until then, commands should be fairly simply
'Understood. Redirect any questions either to "Http://www.dbfinteractive.com"
'Or to blitzamateur@yahoo[dot]com
Dim shared as integer ptr buffer
dim shared as integer GFXWID, GFXHT, GFXWIDH, GFXHTH, CurColor, CLEARCOUNT
declare sub Graphics(ByVal wid as integer, ByVal ht as integer, Byval appname as string)
declare sub FlipSurf()
declare sub ClsSurf()
declare sub Plot(ByVal x as integer, ByVal y as integer)
declare sub ColorSet(ByVal r as integer, ByVal g as integer, ByVal b as integer)
declare sub DrawLine(ByVal x1 as single, ByVal y1 as single, ByVal x2 as single, ByVal y2 as single)
declare sub Oval(ByVal x as single, ByVal y as single, ByVal w as single, ByVal h as single)
declare function GetVsyncRate()
Sub Graphics(ByVal Wid as integer, ByVal Ht as integer, ByVal AppName as string="FB w/ TinyPTC")
if ptc_open(AppName, Wid, Ht) = 0 then
print "Cannot open graphics display at "+str(wid)+", "+str(ht)
sleep
end -1
endif
buffer = callocate(wid*ht, Len(integer))
CLEARCOUNT = wid*ht*Len(integer)
GFXWID = Wid
GFXHT = Ht
GFXWIDH = GFXWID shr 1
GFXHTH = GFXHT shr 1
End Sub
Sub FlipSurf()
ptc_update(buffer)
End Sub
Sub ClsSurf()
clear *buffer, 0, CLEARCOUNT
End Sub
Sub Plot(ByVal x as integer, ByVal y as integer)
buffer[(y*GFXWID+x)] = CurColor
End Sub
Sub ColorSet(ByVal r as integer, ByVal g as integer, ByVal b as integer)
CurColor = ( r shl 16 ) + ( g shl 8 ) + b
End Sub
Sub Oval (ByVal x as single, ByVal y as single, ByVal w as single, ByVal h as single)
End Sub
Sub DrawLine(ByVal x1 as single,ByVal y1 as single,ByVal x2 as single,ByVal y2 as single)
dim temp as single
dim xd as double
dim yd as double
dim y as double
dim x as double
dim xs as double
dim ys as double
if x2 < x1 then
xd = abs(x1-x2)
else
xd = abs(x2-x1)
endif
if y2 < y1 then
yd = abs(y1-y2)
else
yd = abs(y2-y1)
endif
if xd > yd then
if x2 < x1 then
temp = x1
x1 = x2
x2 = temp
temp = y1
y1 = y2
y2 = temp
endif
xd = abs(x2-x1)
yd = abs(y2-y1)
ys = yd/xd
y=y1
for x=x1 to x2
buffer[cint(y+.49)*GFXWID+cint(x+.49)] = CurColor
y=y+ys
next
else
if y2 < y1 then
temp = x1
x1 = x2
x2 = temp
temp = y1
y1 = y2
y2 = temp
endif
xd = abs(x2-x1)
yd = abs(y2-y1)
xs = xd/yd
x=x1
for y=y1 to y2
buffer[cint(y+.49)*GFXWID+cint(x+.49)] = CurColor
x = x + xs
next
endif
end sub
function getvsyncrate()
dim ttime as double
dim count as integer
ttime = timer
count = 0
if WAIT(&h3da, 8)=0 then ttime = timer
do
WAIT(&h3da, 8)
'out(&h3da, 0)
count = count + 1
print count
print count
loop until timer-ttime >= 1.0
return count-1
end function
Rand.bi
declare function Rand(ByVal lower as integer, byVal upper as integer)
declare function FRand(ByVal lower as double, byVal upper as double) as double
Declare sub SeedRnd(ByVal seed as double)
sub SeedRnd(byval seed as double)
randomize seed
end sub
function Rand(ByVal lower as integer, ByVal upper as integer)
dim temp as integer
if upper < lower then
temp=upper
upper=lower
lower=temp
endif
dim value as integer
dim dist as integer
value=lower
dist = abs(lower-upper)
return (rnd(1)*dist) + value
End function
function FRand(ByVal lower as double, ByVal upper as double) as double
dim temp as double
if upper < lower then
temp=upper
upper=lower
lower=temp
endif
dim value as double
dim dist as double
value=lower
dist = abs(lower-upper)
return (rnd(1)*dist) + value
End function
-
Thanks BA :)
-
Mmm,. I think even with timing to refresh rate, there will be a problem. I checked this programm a lot, set it to my refresh rate and there was still the sync line moving down in that flashing. A little value higher it moves up. You can't keep it steady. Actually, the problem is that someone can never (or not?) time exactly at 75 for example, there is some loss. Still, if the true vsync worked, it would be the most suitable way to solve the problem. Someone told me to use DirectDraw for getting vsync, but it might be a fuzz. I am used to SDL/TinyPTC. I wish there was a way here (maybe it will and I'll search and ask if I ever get a time now ;P)
-
Something worth mentioning: If you fiddle with a tming setup such as this, and when you don't have your colors changing that drastically every frame, the vsync lines almost disappear.
-
How experimental is FreeBASIC and the includes and headers etc etc. Maybe as FB is still in it's beta years, there's some stuff thats been overlooked, and they aren't aware of certain stuff. Just a thought.
-
Well if TinyPTC doesnt wait for the Vsync, which it appears your saying it doesnt, then it does the same as blitz when you do flip 0, it's just that because FB & TinyPTC are so much faster your seeing the "tearing" effect that is caused. Alot of games have the option to turn vsync on or off, the reason most have it off is for speed and on for to stop graphic tears across the screen.
-
Well if TinyPTC doesnt wait for the Vsync, which it appears your saying it doesnt, then it does the same as blitz when you do flip 0, it's just that because FB & TinyPTC are so much faster your seeing the "tearing" effect that is caused. Alot of games have the option to turn vsync on or off, the reason most have it off is for speed and on for to stop graphic tears across the screen.
That's the whole point of the post Jon. Some guys turn off the vsynch on their gfx cards and it seems impossible to lock the program into a steady frame rate. What is needed is a procedure to check the status of the scan.
< AMIGA >
wait:
btst #5,$dff01f ; vbl interrupt
beq.s wait
< /AMIGA >
Something like that would be just fine.
-
Ah so what you want is to lock the demos update rate to a set speed so in theory it runs the same speed for everyone but doesn't produce the tearing effect if they have vsync off ?
Getting everything to look like it's moving the same speed uses delta timing as mentioned before but I have no idea how you can lock to a set screen update speed if vsync is off. I dont think it can be very easy if even possible but maybe some form of timer delay loop to ensure the update occurs at set intervals like some of the old blitz timing code use to do before everyone went delta timing. Think I have an old source with the stuff in you might be able to convert will see if I can dig it out, perhaps using a combo of both might work.
[Edit]
Right here's what was done in blitz2d to attempt to keep games updating at a set speed on different hardware.
fpstimer=CreateTimer(60) ; Create a timer that cycles at 60
; Then in main loop
Repeat
frames = WaitTimer(fpstimer)
For t = 1 To frames
; Update stuff.
Next
; render game screen
Gosub render
Until quit=True
Dont know if FB has anything like Waittimer() ? Or if this could be adapted but I cant think of anything else ???
-
FB has a Wait command but it seems impossible to tie this down to a specific frame rate without getting the odd glitch and tearing in the screen display.