@@ -12,16 +12,21 @@ class FrameRateManager {
12
12
static inline final UPDATE_LOAD_COEFF : Float = 0.75 ;
13
13
static inline final MAX_UPDATE_COUNT : Int = 4 ;
14
14
15
- final update : () -> Void ;
15
+ static inline final MIN_UPDATE_TIME : Float = 4 ;
16
+ static inline final MAX_FRAMERATE_RATIO : Float = 4 ;
17
+
18
+ final update : (substepRatio : Float ) -> Void ;
16
19
final draw : () -> Void ;
17
20
var targetInterval : Float = 1000 / 60 ;
18
21
var prevTime : Float ;
22
+ var lastDrawBegin : Float ;
23
+ var estimatedUpdateTime : Float ;
19
24
var running : Bool ;
20
25
var count : Int = 0 ;
21
26
22
27
public var doNotAdjust : Bool = false ;
23
28
24
- public function new (update : () -> Void , draw : () -> Void ) {
29
+ public function new (update : (substepRatio : Float ) -> Void , draw : () -> Void ) {
25
30
this .update = update ;
26
31
this .draw = draw ;
27
32
}
@@ -30,6 +35,7 @@ class FrameRateManager {
30
35
if (running )
31
36
return ;
32
37
prevTime = now () - targetInterval ;
38
+ estimatedUpdateTime = targetInterval ;
33
39
running = true ;
34
40
Browser .window .setTimeout (loop , 0 );
35
41
}
@@ -47,31 +53,70 @@ class FrameRateManager {
47
53
function loop (): Void {
48
54
if (! running )
49
55
return ;
56
+ count ++ ;
50
57
if (doNotAdjust ) {
51
- doFunc (update );
58
+ doFunc (() -> update ( 1 ) );
52
59
doFunc (draw );
53
60
} else {
54
61
final currentTime = now ();
55
- var updated = false ;
56
- var updateCount = 0 ;
57
- while (currentTime - prevTime > targetInterval * 0.5 ) {
58
- updateCount ++ ;
59
- doFunc (update );
60
- updated = true ;
61
- prevTime + = targetInterval ;
62
- final now = now ();
63
- final updateTime = now - currentTime ;
64
- final maxConsecutiveUpdates = count > 30 ? MAX_UPDATE_COUNT : 1 ;
65
- if (updateTime > targetInterval * UPDATE_LOAD_COEFF || updateCount >= maxConsecutiveUpdates ) { // overloaded
66
- if (prevTime < now - targetInterval ) { // do not accumulate too much
67
- prevTime = now - targetInterval ;
68
- }
69
- break ;
62
+
63
+ final maxDrawBegin = max (lastDrawBegin + targetInterval * MAX_FRAMERATE_RATIO , currentTime + MIN_UPDATE_TIME );
64
+ final maxUpdateCount = count < 10 ? 1 : max (1 , Math .round ((maxDrawBegin - currentTime ) / estimatedUpdateTime ));
65
+ final idealUpdateCount = Math .round ((currentTime - prevTime ) / max (targetInterval * 0.01 ,
66
+ targetInterval - estimatedUpdateTime ));
67
+ final updateCount = min (idealUpdateCount , maxUpdateCount );
68
+
69
+ if (updateCount > 0 ) {
70
+ var p = currentTime ;
71
+ var nextLast = false ;
72
+ for (i in 0 ... updateCount ) {
73
+ doFunc (() -> update (nextLast ? 1 : (i + 1 ) / updateCount ));
74
+ final n = now ();
75
+ final updateTime = n - p ;
76
+ estimatedUpdateTime + = (updateTime - estimatedUpdateTime ) * 0.5 ;
77
+ p = n ;
78
+ prevTime + = targetInterval ;
79
+ if (nextLast )
80
+ break ;
81
+ if (n > maxDrawBegin )
82
+ nextLast = true ;
70
83
}
71
- }
72
- if (updated ) {
84
+ prevTime = max (prevTime , p - max (targetInterval * MAX_FRAMERATE_RATIO , MIN_UPDATE_TIME ));
85
+ // trace(prevTime + " " + p + " " + (p - prevTime) + " behind " + (maxDrawBegin - p) + " " + maxUpdateCount + " " +
86
+ // idealUpdateCount);
87
+ lastDrawBegin = p ;
73
88
doFunc (draw );
74
89
}
90
+
91
+ // final maxConsecutiveUpdates = count > 10 ? MAX_UPDATE_COUNT : 1;
92
+ // final updateCount = min(MAX_UPDATE_COUNT, Math.round(idealUpdateCount));
93
+ // if (updateCount > 0) {
94
+ // for (i in 0...updateCount) {
95
+ // doFunc(update);
96
+ // prevTime += targetInterval;
97
+ // }
98
+ // }
99
+
100
+ // while (currentTime - prevTime > targetInterval * 0.5) {
101
+ // updateCount++;
102
+ // doFunc(update);
103
+ // updated = true;
104
+ // prevTime += targetInterval;
105
+ // final now = now();
106
+ // final updateTime = now - currentTime;
107
+ // estimatedUpdateTime = max(estimatedUpdateTime * 0.9, updateTime);
108
+ // final maxConsecutiveUpdates = count > 30 ? MAX_UPDATE_COUNT : 1;
109
+ // if (updateTime > targetInterval * UPDATE_LOAD_COEFF || updateCount >= maxConsecutiveUpdates) { // overloaded
110
+ // if (prevTime < now - targetInterval) { // do not accumulate too much
111
+ // prevTime = now - targetInterval;
112
+ // }
113
+ // break;
114
+ // }
115
+ // }
116
+ // if (updated) {
117
+ // lastDrawBegin = now();
118
+ // doFunc(draw);
119
+ // }
75
120
}
76
121
Browser .window .requestAnimationFrame (cast loop );
77
122
}
@@ -89,6 +134,6 @@ class FrameRateManager {
89
134
}
90
135
91
136
extern inline function now (): Float {
92
- return Date .now ();
137
+ return Browser . window . performance .now ();
93
138
}
94
139
}
0 commit comments