diff --git a/arcade/application.py b/arcade/application.py index 3b158e385a..89e6579065 100644 --- a/arcade/application.py +++ b/arcade/application.py @@ -256,7 +256,8 @@ def __init__( # If more time resolution is needed in fixed updates, devs can do 'sub-stepping'. self._fixed_rate = fixed_rate self._fixed_frame_cap = fixed_frame_cap - self.set_update_rate(update_rate) + # self.set_update_rate(update_rate) + pyglet.clock.schedule_interval(self._next_frame, 1/60) self.set_vsync(vsync) @@ -527,32 +528,32 @@ def _dispatch_updates(self, delta_time: float) -> None: fixed_count += 1 self.dispatch_event("on_update", GLOBAL_CLOCK.delta_time) - def set_update_rate(self, rate: float) -> None: - """ - Set how often the on_update function should be dispatched. - For example:: - - # Set the update rate to 60 times per second. - self.set_update_rate(1 / 60) - - Args: - rate: Update frequency in seconds - """ - self._update_rate = rate - pyglet.clock.unschedule(self._dispatch_updates) - pyglet.clock.schedule_interval(self._dispatch_updates, rate) - - def set_draw_rate(self, rate: float) -> None: - """ - Set how often the on_draw function should be run. - For example:: - - # Set the draw rate to 60 frames per second. - set.set_draw_rate(1 / 60) - """ - self._draw_rate = rate - pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows) - pyglet.clock.schedule_interval(pyglet.app.event_loop._redraw_windows, self._draw_rate) + # def set_update_rate(self, rate: float) -> None: + # """ + # Set how often the on_update function should be dispatched. + # For example:: + + # # Set the update rate to 60 times per second. + # self.set_update_rate(1 / 60) + + # Args: + # rate: Update frequency in seconds + # """ + # self._update_rate = rate + # pyglet.clock.unschedule(self._dispatch_updates) + # pyglet.clock.schedule_interval(self._dispatch_updates, rate) + + # def set_draw_rate(self, rate: float) -> None: + # """ + # Set how often the on_draw function should be run. + # For example:: + + # # Set the draw rate to 60 frames per second. + # set.set_draw_rate(1 / 60) + # """ + # self._draw_rate = rate + # pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows) + # pyglet.clock.schedule_interval(pyglet.app.event_loop._redraw_windows, self._draw_rate) def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> EVENT_HANDLE_STATE: """ @@ -1019,6 +1020,19 @@ def hide_view(self) -> None: self.remove_handlers(self._current_view) self._current_view = None + def _next_frame(self, delta_time: float) -> None: + """ + Internal method called by Pyglet's clock to advance the next frame. + + This method exists to ensure that exactly one update and one draw + is called per frame. Generic interval events are not stable enough + to ensure this. + """ + # print("next frame", delta_time) + self._dispatch_updates(delta_time) + self.dispatch_event("on_draw") + self.flip() + def flip(self) -> None: """ Present the rendered content to the screen. diff --git a/arcade/window_commands.py b/arcade/window_commands.py index a739dd5116..775b85201f 100644 --- a/arcade/window_commands.py +++ b/arcade/window_commands.py @@ -134,7 +134,7 @@ def run(view: View | None = None) -> None: if window.context: active.on_draw() - # windwow could be closed in on_draw + # window could be closed in on_draw if window.context: window.flip() @@ -143,42 +143,43 @@ def run(view: View | None = None) -> None: else: import sys - if sys.platform != "win32": - # For non windows platforms, just do pyglet run - pyglet.app.run(window._draw_rate) - else: - # Ok, some Windows platforms have a timer resolution > 15 ms. That can - # drop our FPS to 32 FPS or so. This reduces resolution so we can keep - # FPS up. - import contextlib - import ctypes - from ctypes import wintypes - - winmm = ctypes.WinDLL("winmm") - - class TIMECAPS(ctypes.Structure): - _fields_ = (("wPeriodMin", wintypes.UINT), ("wPeriodMax", wintypes.UINT)) - - def _check_time_err(err, func, args): - if err: - raise WindowsError("%s error %d" % (func.__name__, err)) - return args - - winmm.timeGetDevCaps.errcheck = _check_time_err - winmm.timeBeginPeriod.errcheck = _check_time_err - winmm.timeEndPeriod.errcheck = _check_time_err - - @contextlib.contextmanager - def timer_resolution(msecs=0): - caps = TIMECAPS() - winmm.timeGetDevCaps(ctypes.byref(caps), ctypes.sizeof(caps)) - msecs = min(max(msecs, caps.wPeriodMin), caps.wPeriodMax) - winmm.timeBeginPeriod(msecs) - yield - winmm.timeEndPeriod(msecs) - - with timer_resolution(msecs=10): - pyglet.app.run(window._draw_rate) + pyglet.app.run(None) + # if sys.platform != "win32": + # # For non windows platforms, just do pyglet run + # pyglet.app.run(window._draw_rate) + # else: + # # Ok, some Windows platforms have a timer resolution > 15 ms. That can + # # drop our FPS to 32 FPS or so. This reduces resolution so we can keep + # # FPS up. + # import contextlib + # import ctypes + # from ctypes import wintypes + + # winmm = ctypes.WinDLL("winmm") + + # class TIMECAPS(ctypes.Structure): + # _fields_ = (("wPeriodMin", wintypes.UINT), ("wPeriodMax", wintypes.UINT)) + + # def _check_time_err(err, func, args): + # if err: + # raise WindowsError("%s error %d" % (func.__name__, err)) + # return args + + # winmm.timeGetDevCaps.errcheck = _check_time_err + # winmm.timeBeginPeriod.errcheck = _check_time_err + # winmm.timeEndPeriod.errcheck = _check_time_err + + # @contextlib.contextmanager + # def timer_resolution(msecs=0): + # caps = TIMECAPS() + # winmm.timeGetDevCaps(ctypes.byref(caps), ctypes.sizeof(caps)) + # msecs = min(max(msecs, caps.wPeriodMin), caps.wPeriodMax) + # winmm.timeBeginPeriod(msecs) + # yield + # winmm.timeEndPeriod(msecs) + + # with timer_resolution(msecs=10): + # pyglet.app.run(None) def exit() -> None: