def do_flip(self, block=True): # call the flip EventLoop.window.dispatch('on_flip') # TODO: use sync events instead! if block: # draw a transparent point # position glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, "\x00\x00\x00\x0a\x00\x00\x00\x0a") # color glVertexAttrib4f(3, 0.0, 0.0, 0.0, 0.0) glDrawArrays(GL_POINTS, 0, 1) # wait for flip then point to draw glFinish() # record the time immediately self.last_flip = event_time(clock.now(), 0.0) else: # we didn't block, so set to predicted flip time self.last_flip = event_time(max(self._next_flip_time, clock.now()), 0.0) # update flip times self._next_flip_time = self.last_flip['time'] + self.flip_interval self._next_draw_time = self.last_flip['time'] + self.flip_interval/2. self._did_draw = False return self.last_flip
def do_flip(self, block=True): # call the flip EventLoop.window.dispatch('on_flip') # TODO: use sync events instead! if block: # draw a transparent point # position glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, "\x00\x00\x00\x0a\x00\x00\x00\x0a") # color glVertexAttrib4f(3, 0.0, 0.0, 0.0, 0.0) glDrawArrays(GL_POINTS, 0, 1) # wait for flip then point to draw glFinish() # record the time immediately self.last_flip = event_time(clock.now(), 0.0) else: # we didn't block, so set to predicted flip time self.last_flip = event_time(max(self._next_flip_time, clock.now()), 0.0) # update flip times self._next_flip_time = self.last_flip['time'] + self.flip_interval self._next_draw_time = self.last_flip['time'] + self.flip_interval / 2. self._did_draw = False return self.last_flip
def build(self): # set fullscreen and resolution if self.exp._fullscreen is not None: Window.fullscreen = self.exp._fullscreen if self.exp._resolution is not None: Window.system_size = self.exp._resolution # handle setting the bg color self.set_background_color() # base layout uses positional placement self.wid = FloatLayout() Window._system_keyboard.bind(on_key_down=self._on_key_down, on_key_up=self._on_key_up) Window.bind(on_motion=self._on_motion, mouse_pos=self._on_mouse_pos, on_resize=self._on_resize) self.current_touch = None # set starting times self._last_time = clock.now() self._last_kivy_tick = clock.now() # use our idle callback (defined below) kivy.base.EventLoop.set_idle_callback(self._idle_callback) # get start of event loop EventLoop.bind(on_start=self._on_start) # set width and height self.exp._screen._set_width(Window.width) self.exp._screen._set_height(Window.height) return self.wid
def build(self): self.wid = FloatLayout() Window._system_keyboard.bind(on_key_down=self._on_key_down, on_key_up=self._on_key_up) Window.bind(on_motion=self._on_motion, mouse_pos=self._on_mouse_pos, on_resize=self._on_resize) self.current_touch = None self._last_time = clock.now() self._last_kivy_tick = clock.now() kivy.base.EventLoop.set_idle_callback(self._idle_callback) print 1.0 / self.calc_flip_interval() # ... return self.wid
def build(self): self.wid = FloatLayout() Window._system_keyboard.bind(on_key_down=self._on_key_down, on_key_up=self._on_key_up) Window.bind(on_motion=self._on_motion, mouse_pos=self._on_mouse_pos, on_resize=self._on_resize) self.current_touch = None self._last_time = clock.now() self._last_kivy_tick = clock.now() kivy.base.EventLoop.set_idle_callback(self._idle_callback) print 1.0 / self.calc_flip_interval() #... return self.wid
def _on_start(self, *pargs): # print('ON_START:', self.exp._root_executor) self.get_flip_interval() self.do_flip(block=True) # start the state machine self.exp._root_executor.enter(clock.now() + 0.25)
def _on_start(self, *pargs): # print "on_start" # self.exp._root_state.enter(clock.now() + 1.0) self.get_flip_interval() self.do_flip(block=True) # start the state machine self.exp._root_executor.enter(clock.now() + 0.25)
def _on_start(self, *pargs): # print "on_start" # self.exp._root_state.enter(clock.now() + 1.0) self.blocking_flip() # hack to wait until fullscreen on OSX if True: # not (platform in ('macosx',) and Window.fullscreen): print "Estimated Refresh Rate:", 1.0 / self.calc_flip_interval() self.exp._root_executor.enter(clock.now() + 0.25)
def blocking_flip(self): EventLoop.window.dispatch("on_flip") # glEnableVertexAttribArray(0) # kivy has this enabled already glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, "\x00\x00\x00\x0a\x00\x00\x00\x0a") # Position glVertexAttrib4f(3, 0.0, 0.0, 0.0, 0.0) # Color glDrawArrays(GL_POINTS, 0, 1) # glDisableVertexAttribArray(0) # kivy needs this to stay enabled glFinish() self.last_flip = event_time(clock.now(), 0.0) return self.last_flip
def start(self): # open all the logs # (this will call begin_log for entire state machine) self._root_state.begin_log() # clone the root state in prep for starting the state machine self._root_executor = self._root_state._clone(None) # start it up self._root_executor.enter(clock.now() + 0.25)
def blocking_flip(self): EventLoop.window.dispatch('on_flip') #glEnableVertexAttribArray(0) # kivy has this enabled already glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, "\x00\x00\x00\x0a\x00\x00\x00\x0a") # Position glVertexAttrib4f(3, 0.0, 0.0, 0.0, 0.0) # Color glDrawArrays(GL_POINTS, 0, 1) #glDisableVertexAttribArray(0) # kivy needs this to stay enabled glFinish() self.last_flip = event_time(clock.now(), 0.0) return self.last_flip
def build(self): # base layout uses positional placement self.wid = FloatLayout() Window._system_keyboard.bind(on_key_down=self._on_key_down, on_key_up=self._on_key_up) Window.bind(on_motion=self._on_motion, mouse_pos=self._on_mouse_pos, on_resize=self._on_resize) self.current_touch = None # set starting times self._last_time = clock.now() self._last_kivy_tick = clock.now() # use our idle callback (defined below) kivy.base.EventLoop.set_idle_callback(self._idle_callback) # get start of event loop EventLoop.bind(on_start=self._on_start) return self.wid
def _on_resize(self, *pargs): # handle the resize self.exp._screen._set_width(Window.width) self.exp._screen._set_height(Window.height) # second half of OSX fullscreen hack that may no longer be needed if platform in ('macosx',) and Window.fullscreen and \ not self.exp._root_executor._enter_time and \ not self.exp._root_executor._active: self.exp._root_executor.enter(clock.now() + 0.25) # we need a redraw here self.do_flip(block=True)
def _on_resize(self, *pargs): # handle the resize self.width_ref.dep_changed() self.height_ref.dep_changed() # second half of OSX fullscreen hack that may no longer be needed if platform in ('macosx',) and Window.fullscreen and \ not self.exp._root_executor._enter_time and \ not self.exp._root_executor._active: print "Estimated Refresh Rate:", 1.0 / self.calc_flip_interval() self.exp._root_executor.enter(clock.now() + 0.25) # we need a redraw here EventLoop.window.dispatch('on_flip')
def _on_resize(self, *pargs): # handle the resize self.exp._screen._set_width(Window.width) self.exp._screen._set_height(Window.height) # second half of OSX fullscreen hack that may no longer be needed if platform in ('macosx',) and Window.fullscreen and \ not self.exp._root_executor._enter_time and \ not self.exp._root_executor._active: print "Estimated Refresh Rate:", 1.0 / self.calc_flip_interval() self.exp._root_executor.enter(clock.now() + 0.25) # we need a redraw here EventLoop.window.dispatch('on_flip')
def blocking_flip(self): # TODO: use sync events instead! EventLoop.window.dispatch('on_flip') # draw a transparent point glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, "\x00\x00\x00\x0a\x00\x00\x00\x0a") # Position glVertexAttrib4f(3, 0.0, 0.0, 0.0, 0.0) # Color glDrawArrays(GL_POINTS, 0, 1) # wait for flip and point to draw glFinish() # record the time immediately self.last_flip = event_time(clock.now(), 0.0) return self.last_flip
def run(self, trace=False): self._current_state = None if trace: self._root_state.tron() self._root_state.begin_log() try: # start the first state (that's the root state) self._root_state.enter(clock.now() + 1.0) # kivy main loop self._app.run() except: if self._current_state is not None: self._current_state.print_traceback() raise self._root_state.end_log(self._csv) self.close_state_loggers(self._csv)
def build(self): # set fullscreen and resolution if self.exp._fullscreen is not None: # set based on the experiment preference Window.fullscreen = self.exp._fullscreen if Window.fullscreen == False: # make sure we have a border Window.borderless = False if self.exp._resolution is not None: Window.system_size = self.exp._resolution # handle setting the bg color self.set_background_color() # base layout uses positional placement self.wid = FloatLayout() Window._system_keyboard.bind(on_key_down=self._on_key_down, on_key_up=self._on_key_up) Window.bind(on_motion=self._on_motion, mouse_pos=self._on_mouse_pos, on_resize=self._on_resize) self.current_touch = None # set starting times self._post_dispatch_time = clock.now() # use our idle callback (defined below) kivy.base.EventLoop.set_idle_callback(self._idle_callback) # get start of event loop EventLoop.bind(on_start=self._on_start) # set width and height self.exp._screen._set_width(Window.width) self.exp._screen._set_height(Window.height) scale._calc_scale_factor(Window.width, Window.height) self.exp._sysinfo.update({ "screen_size": [Window.width, Window.height], "scale_factor": scale._scale_factor }) self.exp._write_sysinfo() return self.wid
def build(self): # set fullscreen and resolution if self.exp._fullscreen is not None: Window.fullscreen = self.exp._fullscreen if self.exp._resolution is not None: Window.system_size = self.exp._resolution # handle setting the bg color self.set_background_color() # base layout uses positional placement self.wid = FloatLayout() Window._system_keyboard.bind(on_key_down=self._on_key_down, on_key_up=self._on_key_up) Window.bind(on_motion=self._on_motion, mouse_pos=self._on_mouse_pos, on_resize=self._on_resize) self.current_touch = None # set starting times self._post_dispatch_time = clock.now() # use our idle callback (defined below) kivy.base.EventLoop.set_idle_callback(self._idle_callback) # get start of event loop EventLoop.bind(on_start=self._on_start) # set width and height self.exp._screen._set_width(Window.width) self.exp._screen._set_height(Window.height) scale._calc_scale_factor(Window.width, Window.height) self.exp._sysinfo.update({"screen_size":[Window.width, Window.height],}) self.exp._write_sysinfo() return self.wid
def _idle_callback(self, event_loop): # record the time range self._new_time = clock.now() time_err = (self._new_time - self._last_time) / 2.0 self.event_time = event_time(self._last_time + time_err, time_err) clock.tick() ready_for_video = (self._new_time - self.last_flip["time"] >= self.flip_interval) ready_for_kivy_tick = ready_for_video and (self._new_time - self._last_kivy_tick >= self.flip_interval) need_draw = False for video in self.video_queue: if (not video.drawn and ((self.pending_flip_time is None and self._new_time >= video.flip_time - self.flip_interval / 2.0) or video.flip_time == self.pending_flip_time)): video.update_cb() need_draw = True video.drawn = True self.pending_flip_time = video.flip_time else: break do_kivy_tick = ready_for_kivy_tick or need_draw if do_kivy_tick: _kivy_clock.tick() self._last_kivy_tick = self._new_time event_loop.dispatch_input() if do_kivy_tick: Builder.sync() _kivy_clock.tick_draw() Builder.sync() kivy_needs_draw = EventLoop.window.canvas.needs_redraw or need_draw #print (_kivy_clock.get_fps(), _kivy_clock.get_rfps(), self._new_time) #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else: kivy_needs_draw = False if kivy_needs_draw: EventLoop.window.dispatch('on_draw') if ready_for_video: need_flip = kivy_needs_draw and self.pending_flip_time is None flip_time_callbacks = [] for video in self.video_queue: if video.drawn and video.flip_time == self.pending_flip_time: need_flip = True if video.flip_time_cb is not None: flip_time_callbacks.append(video.flip_time_cb) video.flipped = True else: break while len(self.video_queue) and self.video_queue[0].flipped: del self.video_queue[0] if need_flip: if len(flip_time_callbacks): #print "BLOCKING FLIP!" #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! self.blocking_flip() #TODO: use sync events instead! for cb in flip_time_callbacks: cb(self.last_flip) else: #print "FLIP!" #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EventLoop.window.dispatch('on_flip') self.last_flip = event_time(clock.now(), 0.0) self.pending_flip_time = None # save the time self._last_time = self._new_time # exit if experiment done if not self.exp._root_state._active: self.stop() # give time to other threads clock.usleep(250)
def _idle_callback(self, event_loop): # record the time range self._new_time = clock.now() time_err = (self._new_time - self._last_time) / 2.0 self.event_time = event_time(self._last_time + time_err, time_err) # call any of our scheduled events that are ready clock.tick() # see if we're ready for video ready_for_video = ((self._new_time - self.last_flip["time"]) >= (self.flip_interval - FLIP_TIME_MARGIN)) # see if the kivy clock needs a tick # throttled by flip interval ready_for_kivy_tick = ready_for_video and (self._new_time - self._last_kivy_tick >= self.flip_interval) # prepare for every video to be drawn on the next flip need_draw = False for video in self.video_queue: if (not video.drawn and ((self.pending_flip_time is None and self._new_time >= (video.flip_time - (self.flip_interval / 2.0))) or video.flip_time == self.pending_flip_time)): # prepare that video change video.update_cb() need_draw = True video.drawn = True # save the pending time so all other changes # for that time will also run self.pending_flip_time = video.flip_time else: # either none are ready or the remaining are # for a subsequent flip break # do a kivy tick if we're going to be drawing or enough time # has passed (see above) do_kivy_tick = ready_for_kivy_tick or need_draw if do_kivy_tick: # tick the kivy clock _kivy_clock.tick() self._last_kivy_tick = self._new_time # dispatch input events event_loop.dispatch_input() # process the builder and check for kivy draws if do_kivy_tick: Builder.sync() _kivy_clock.tick_draw() Builder.sync() kivy_needs_draw = EventLoop.window.canvas.needs_redraw or need_draw # print (_kivy_clock.get_fps(), # _kivy_clock.get_rfps(), self._new_time) else: kivy_needs_draw = False # dispatch draw if necessary if kivy_needs_draw: EventLoop.window.dispatch('on_draw') # handle video and flips if ready_for_video: # we need flip if kivy needs one need_flip = kivy_needs_draw and self.pending_flip_time is None flip_time_callbacks = [] for video in self.video_queue: if video.drawn and video.flip_time == self.pending_flip_time: # a smile video change is ready, so we need flip need_flip = True # append the flip time callback if video.flip_time_cb is not None: flip_time_callbacks.append(video.flip_time_cb) # mark that video as flipped (it's gonna be) video.flipped = True else: # no more of the videos could match, so break break # remove any video change that's gonna be flipped while len(self.video_queue) and self.video_queue[0].flipped: del self.video_queue[0] # do flip if necessary if need_flip: # test if blocking or non-blocking flip # do a blocking if: # 1) The pending flip is outside a single flip interval # AND # 2) Forcing a blocking flip_interval # OR # 3) We have a specific flip callback request and we # are not forcing a non-blocking flip if (self.pending_flip_time > (self.last_flip['time'] + self.flip_interval + FLIP_TIME_MARGIN)) and \ (self.force_blocking_flip or (len(flip_time_callbacks) and not self.force_nonblocking_flip)): # print "BLOCKING FLIP!" self.blocking_flip() # for cb in flip_time_callbacks: # cb(self.last_flip) else: # non-blicking flip # print "FLIP!" EventLoop.window.dispatch('on_flip') self.last_flip = event_time(clock.now(), 0.0) # still may need to update flip_time_callbacks # even though they will be wrong for cb in flip_time_callbacks: cb(self.last_flip) # tell refs that last_flip updated self.last_flip_ref.dep_changed() # no longer pending flip self.pending_flip_time = None # save the time self._last_time = self._new_time # exit if experiment done if not self.exp._root_executor._active: if self.exp._root_executor._enter_time: # stop if we're not active, but we have an enter time self.stop() # give time to other threads clock.usleep(250)
def _idle_callback(self, event_loop): # record the time range self._new_time = clock.now() time_err = (self._new_time - self._last_time) / 2.0 self.event_time = event_time(self._last_time + time_err, time_err) # call any of our scheduled events that are ready clock.tick() # see if we're ready for video ready_for_video = ((self._new_time - self.last_flip["time"]) >= (self.flip_interval - FLIP_TIME_MARGIN)) # see if the kivy clock needs a tick # throttled by flip interval ready_for_kivy_tick = ready_for_video and ( self._new_time - self._last_kivy_tick >= self.flip_interval) # prepare for every video to be drawn on the next flip need_draw = False for video in self.video_queue: if (not video.drawn and ((self.pending_flip_time is None and self._new_time >= (video.flip_time - (self.flip_interval / 2.0))) or video.flip_time == self.pending_flip_time)): # prepare that video change video.update_cb() need_draw = True video.drawn = True # save the pending time so all other changes # for that time will also run self.pending_flip_time = video.flip_time else: # either none are ready or the remaining are # for a subsequent flip break # do a kivy tick if we're going to be drawing or enough time # has passed (see above) # but only tick and draw once before a flip do_kivy_tick = ready_for_kivy_tick or need_draw if do_kivy_tick: # tick the kivy clock _kivy_clock.tick() self._last_kivy_tick = self._new_time # dispatch input events event_loop.dispatch_input() # process the builder and check for kivy draws if do_kivy_tick: Builder.sync() _kivy_clock.tick_draw() Builder.sync() kivy_needs_draw = EventLoop.window.canvas.needs_redraw or need_draw # print (_kivy_clock.get_fps(), # _kivy_clock.get_rfps(), self._new_time) else: kivy_needs_draw = False # dispatch draw if necessary if kivy_needs_draw: EventLoop.window.dispatch('on_draw') # handle video and flips if ready_for_video: # we need flip if kivy needs one need_flip = kivy_needs_draw and self.pending_flip_time is None flip_time_callbacks = [] for video in self.video_queue: if video.drawn and video.flip_time == self.pending_flip_time: # a smile video change is ready, so we need flip need_flip = True # append the flip time callback if video.flip_time_cb is not None: flip_time_callbacks.append(video.flip_time_cb) # mark that video as flipped (it's gonna be) video.flipped = True else: # no more of the videos could match, so break break # remove any video change that's gonna be flipped while len(self.video_queue) and self.video_queue[0].flipped: del self.video_queue[0] # do flip if necessary if need_flip: # test if blocking or non-blocking flip # do a blocking if: # 1) Forcing a blocking flip_interval # OR # 2) We have a specific flip callback request and we # are not forcing a non-blocking flip if self.force_blocking_flip or \ (len(flip_time_callbacks) and not self.force_nonblocking_flip): # print "BLOCKING FLIP!" self.blocking_flip() else: # non-blocking flip # print "FLIP!" EventLoop.window.dispatch('on_flip') self.last_flip = event_time(clock.now(), 0.0) # still may need to update flip_time_callbacks # even though they may be wrong for non-blocking flips for cb in flip_time_callbacks: cb(self.last_flip) # tell refs that last_flip updated self.exp._screen._set_last_flip(self.last_flip) # no longer pending flip self.pending_flip_time = None # save the time self._last_time = self._new_time # exit if experiment done if not self.exp._root_executor._active: if self.exp._root_executor._enter_time: # stop if we're not active, but we have an enter time self.stop() # give time to other threads clock.usleep(IDLE_USLEEP)
def _idle_callback(self, event_loop): # record the time range self._new_time = clock.now() time_err = (self._new_time - self._last_time) / 2.0 self.event_time = event_time(self._last_time + time_err, time_err) clock.tick() ready_for_video = (self._new_time - self.last_flip["time"] >= self.flip_interval) ready_for_kivy_tick = ready_for_video and ( self._new_time - self._last_kivy_tick >= self.flip_interval) need_draw = False for video in self.video_queue: if (not video.drawn and ((self.pending_flip_time is None and self._new_time >= video.flip_time - self.flip_interval / 2.0) or video.flip_time == self.pending_flip_time)): video.update_cb() need_draw = True video.drawn = True self.pending_flip_time = video.flip_time else: break do_kivy_tick = ready_for_kivy_tick or need_draw if do_kivy_tick: _kivy_clock.tick() self._last_kivy_tick = self._new_time event_loop.dispatch_input() if do_kivy_tick: Builder.sync() _kivy_clock.tick_draw() Builder.sync() kivy_needs_draw = EventLoop.window.canvas.needs_redraw or need_draw #print (_kivy_clock.get_fps(), _kivy_clock.get_rfps(), self._new_time) #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else: kivy_needs_draw = False if kivy_needs_draw: EventLoop.window.dispatch('on_draw') if ready_for_video: need_flip = kivy_needs_draw and self.pending_flip_time is None flip_time_callbacks = [] for video in self.video_queue: if video.drawn and video.flip_time == self.pending_flip_time: need_flip = True if video.flip_time_cb is not None: flip_time_callbacks.append(video.flip_time_cb) video.flipped = True else: break while len(self.video_queue) and self.video_queue[0].flipped: del self.video_queue[0] if need_flip: if len(flip_time_callbacks): #print "BLOCKING FLIP!" #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! self.blocking_flip() #TODO: use sync events instead! for cb in flip_time_callbacks: cb(self.last_flip) else: #print "FLIP!" #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EventLoop.window.dispatch('on_flip') self.last_flip = event_time(clock.now(), 0.0) self.pending_flip_time = None # save the time self._last_time = self._new_time # exit if experiment done if not self.exp._root_state._active: self.stop() # give time to other threads clock.usleep(250)
def _idle_callback(self, event_loop): # record the time range self._new_time = clock.now() # call any of our scheduled events that are ready clock.tick() # dispatch input events time_err = (clock.now() - self._post_dispatch_time) / 2.0 self.dispatch_input_event_time = event_time( self._post_dispatch_time + time_err, time_err) event_loop.dispatch_input() self._post_dispatch_time = clock.now() # processing video and drawing can only happen if we have # not already drawn if not self._did_draw: # prepare for every video to be drawn on the next flip for video in self.video_queue: # the desired video time must be after the previous flip # is done, so making sure the next_flip_time is after # ensures this is the case if (video.flip_time - self._next_flip_time) < 0.0: if (not video.drawn and ((self.pending_flip_time is None and self._new_time >= (video.flip_time - (self.flip_interval / 2.0))) or video.flip_time == self.pending_flip_time)): # prepare that video change video.update_cb() # it will be drawn video.drawn = True # save the pending time so all other changes # for that time will also run self.pending_flip_time = video.flip_time else: # either none are ready or the remaining are # for a subsequent flip break else: break # do kivy ticks and draw when we're ready # happens at half the flip interval since last flip if clock.now() >= self._next_draw_time: # tick the kivy clock _kivy_clock.tick() # sync Builder and call tick_draw to prepare to draw Builder.sync() _kivy_clock.tick_draw() Builder.sync() EventLoop.window.dispatch('on_draw') # process smile video callbacks for the upcoming flip self._flip_time_callbacks = [] for video in self.video_queue: if video.drawn and video.flip_time == self.pending_flip_time: # append the flip time callback if video.flip_time_cb is not None: self._flip_time_callbacks.append( video.flip_time_cb) # mark that video as flipped (it's gonna be) video.flipped = True else: # no more of the videos could match, so break break # remove any video change that's gonna be flipped while len(self.video_queue) and self.video_queue[0].flipped: del self.video_queue[0] # we've drawn the one time we can this frame self._did_draw = True # do a flip when we're ready # must have completed draw (this will ensure we don't do double flips # inside the FLIP_TIME_MARGIN b/c did_draw will be reset to False upon # the flip if self._did_draw and \ clock.now() >= self._next_flip_time-FLIP_TIME_MARGIN: # test if blocking or non-blocking flip # do a blocking if: # 1) Forcing a blocking flip_interval # OR # 2) We have a specific flip callback request and we # are not forcing a non-blocking flip if self.force_blocking_flip or \ (len(self._flip_time_callbacks) and not self.force_nonblocking_flip): # do a blocking flip self.do_flip(block=True) else: # do a non-blocking flip self.do_flip(block=False) # still may need to update flip_time_callbacks # even though they may be wrong for non-blocking flips for cb in self._flip_time_callbacks: cb(self.last_flip) # tell refs that last_flip updated self.exp._screen._set_last_flip(self.last_flip) # reset for next flip self.pending_flip_time = None # exit if experiment done if not self.exp._root_executor._active: if self.exp._root_executor._enter_time: # stop if we're not active, but we have an enter time self.stop() # give time to other threads clock.usleep(IDLE_USLEEP) # save the time self._last_time = clock.now() time_err = (self._last_time - self._new_time) / 2.0 self.event_time = event_time(self._new_time + time_err, time_err)
def _idle_callback(self, event_loop): # record the time range self._new_time = clock.now() # call any of our scheduled events that are ready clock.tick() # dispatch input events time_err = (clock.now() - self._post_dispatch_time) / 2.0 self.dispatch_input_event_time = event_time(self._post_dispatch_time + time_err, time_err) event_loop.dispatch_input() self._post_dispatch_time = clock.now() # processing video and drawing can only happen if we have # not already drawn if not self._did_draw: # prepare for every video to be drawn on the next flip for video in self.video_queue: # the desired video time must be after the previous flip # is done, so making sure the next_flip_time is after # ensures this is the case if (video.flip_time - self._next_flip_time) < 0.0: if (not video.drawn and ((self.pending_flip_time is None and self._new_time >= (video.flip_time - (self.flip_interval / 2.0))) or video.flip_time == self.pending_flip_time)): # prepare that video change video.update_cb() # it will be drawn video.drawn = True # save the pending time so all other changes # for that time will also run self.pending_flip_time = video.flip_time else: # either none are ready or the remaining are # for a subsequent flip break else: break # do kivy ticks and draw when we're ready # happens at half the flip interval since last flip if clock.now() >= self._next_draw_time: # tick the kivy clock _kivy_clock.tick() # sync Builder and call tick_draw to prepare to draw Builder.sync() _kivy_clock.tick_draw() Builder.sync() EventLoop.window.dispatch('on_draw') # process smile video callbacks for the upcoming flip self._flip_time_callbacks = [] for video in self.video_queue: if video.drawn and video.flip_time == self.pending_flip_time: # append the flip time callback if video.flip_time_cb is not None: self._flip_time_callbacks.append(video.flip_time_cb) # mark that video as flipped (it's gonna be) video.flipped = True else: # no more of the videos could match, so break break # remove any video change that's gonna be flipped while len(self.video_queue) and self.video_queue[0].flipped: del self.video_queue[0] # we've drawn the one time we can this frame self._did_draw = True # do a flip when we're ready # must have completed draw (this will ensure we don't do double flips # inside the FLIP_TIME_MARGIN b/c did_draw will be reset to False upon # the flip if self._did_draw and \ clock.now() >= self._next_flip_time-FLIP_TIME_MARGIN: # test if blocking or non-blocking flip # do a blocking if: # 1) Forcing a blocking flip_interval # OR # 2) We have a specific flip callback request and we # are not forcing a non-blocking flip if self.force_blocking_flip or \ (len(self._flip_time_callbacks) and not self.force_nonblocking_flip): # do a blocking flip self.do_flip(block=True) else: # do a non-blocking flip self.do_flip(block=False) # still may need to update flip_time_callbacks # even though they may be wrong for non-blocking flips for cb in self._flip_time_callbacks: cb(self.last_flip) # tell refs that last_flip updated self.exp._screen._set_last_flip(self.last_flip) # reset for next flip self.pending_flip_time = None # exit if experiment done if not self.exp._root_executor._active: if self.exp._root_executor._enter_time: # stop if we're not active, but we have an enter time self.stop() # give time to other threads clock.usleep(IDLE_USLEEP) # save the time self._last_time = clock.now() time_err = (self._last_time - self._new_time) / 2.0 self.event_time = event_time(self._new_time + time_err, time_err)