Created
June 19, 2021 07:04
-
-
Save cessor/044620b10be11b73c0459a9505b2caef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Duration(object): | |
''' | |
Calculate duration with 60 FPS (16.66 ms per frame) | |
Make it so that the duration can be compared using >=, | |
so that the NEXT Frame will actually display a stimulus. | |
Example: | |
Suppose you want to display a stimulus after 225 ms. This is technically impossible on a 60hz screen with a synchronized display because each frame takes 0.0167 seconds (16.7ms) to render, and so the stimulus can either draw for 216.7ms or 233.3ms. I discussed with the product owner (Jan Rummel) that we should opt for the earlier stimulus, because otherwise the milliseconds add up. | |
During each frame, an update is sent to the system whether the next | |
stimulus should be displayed during the next frame. | |
If so, the stimulus will draw itself onto the window. | |
The next flip command will then display the stimulus, | |
therefore we need to decide to draw one frame ahead. | |
In other words: | |
225ms is between frame 13 (216.7ms) and frame 14 (233.3ms). | |
Therefore, we draw during frame 13 (216.7ms), so that | |
frame 14 (233.3ms) contains the stimulus. | |
Frame Time ms | |
----------------- | |
... | |
FRAME 10, t=0.1667 | |
DRAW | |
FRAME 11, t=0.1833 | |
DRAW | |
FRAME 12, t=0.2000 | |
DRAW | |
FRAME 13, t=0.2167 # 1. Timeout? | |
DRAW # 2. Draw Here! | |
FRAME 14, t=0.2333 # 3. Frame contains stimulus | |
DRAW | |
FRAME 15, t=0.2500 # 4. Too Late | |
DRAW | |
FRAME 16, t=0.2667 | |
FRAME 17, t=0.2833 | |
1. We need to check whether this frame is hit | |
2. If so, we need to draw the stimulus... | |
3. ...so that the next frame displays it | |
4. This frame would be too late | |
''' | |
FREQUENCY = 1 / 60 * 1000 | |
def __init__(self, duration_ms: int): | |
self._duration_ms = duration_ms | |
self._frames = int(self._duration_ms // self.FREQUENCY) | |
def ms(self): | |
return self._duration_ms | |
def frames(self): | |
return self._frames | |
def frames_elapsed(self, frames: int): | |
return frames >= self._frames | |
def __repr__(self): | |
return f'<Duration: {self._duration_ms} ms ({self._frames} f)>' | |
class Forever(Duration): | |
def __init__(self): | |
super().__init__(0) | |
def frames_elapsed(self, frames): | |
return False | |
def __repr__(self): | |
return '<Forever>' | |
# Add static factory | |
Duration.Forever = Forever |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment