예제 #1
0
    def setup(self):

        ''' 
            process custom settings that might have been set after initializing
            the object.  
        '''
        # check if these parameters / properties / attributes were actually set!
        self.USE_MMAP = getattr(self, 'receive_data_from_matlab', self.USE_MMAP)
        self.SETTINGS.COLOR_TO_USE = getattr(self, 'COLOR_TO_USE', self.SETTINGS.COLOR_TO_USE)

        # add 'abs_plugin_ID' to plugin name.
        self.PLUGIN_NAME = self.PLUGIN_NAME + '-' + str(self.abs_plugin_ID)


        ''' set variables based on init() values. '''
        self.Y_LIMS = [0, self.SETTINGS.WINDOW_HEIGHT_DEFAULT]
        self.SETTINGS.WINDOW_WIDTH_CURRENT = self.SETTINGS.WINDOW_WIDTH_DEFAULT
        self.SETTINGS.WINDOW_HEIGHT_CURRENT = self.SETTINGS.WINDOW_HEIGHT_DEFAULT

        ''' setup mmap or random data interface '''
        status, self.MMAP, self.RANDOM_DATA = setup_incoming_data_interface(self.USE_MMAP, self.PLUGIN_NAME, self.NBR_CHANNELS, self.nPointsToUpdate, self.nPoints, self.SETTINGS.WINDOW_WIDTH_CURRENT, self.SETTINGS.WINDOW_HEIGHT_CURRENT)
        if not status:
             sys.exit(1)


        ''' setup plot queue '''
        self.plot_queue = setup_plotting_queue()


        ''' generate initial positions & colors, and setup VOBs '''
        self.vbo_data, self.vbo_colors, self.x_coords, self.SETTINGS.COLOR_USED = \
            gl_setup_initial_data_and_color_and_vbos(self.nPoints, n_COORDINATES_PER_COLOR, self.NBR_CHANNELS, self.SETTINGS)


        ''' horizontal and vertical lines - setup even if user doesn't want 
            to see them, because we setup key press functions to en-/disable them. '''
        # horizontal line showing the threshold 
        self.line_hor = line_default_horizontal(self)

        # vertical line showing which data point is going to be update next 
        self.line_ver = line_default_vertical(self)

        ''' axes - setup even it user doesn't want to see it, because of kpf. '''
        self.coord_axes, self.y_axis_tics = axes_default_with_y_ticks(self)


        ''' other stuff '''
        # is Tkinter installed and running?
        self.SETTINGS = tkinter_register_with_settings(self.SETTINGS)

        # set the window caption. Can't do it in 'setup_window' because some parameters
        # are not processed there yet.
        self.setup_window_caption()
예제 #2
0
    def purge_plot_queue_if_necessary(self):

		if self.plot_queue_purge_if_size_limit_reached and len(self.plot_queue) > self.plot_queue_size_limit:
			self.plot_queue = setup_plotting_queue()
예제 #3
0
    def on_key_press(self, symbol, modifiers):

        ''' basic kpf '''
        if symbol == key.A: # show / hide axes
            if modifiers == key.MOD_CTRL + self.mod_offset:
                if self.SHOW_AXES:
                    self.coord_axes, self.y_axis_tics, self.SHOW_AXES = False, False, False
                else:
                    self.SHOW_AXES = True
                    self.coord_axes, self.y_axis_tics = axes_default_with_y_ticks(self)

        elif symbol == key.C:
            self.plot_queue = setup_plotting_queue()
            print "Cleared Plot-Queue"        

        elif symbol == key.F: # show / hide FPS display
            self.SHOW_FPS = not self.SHOW_FPS

        elif symbol == key.H: # show help menu
            from pyglet_app_strings import main_help_menu
            # the tkinterface is currently buggy - show console output by default.
            if self.SETTINGS.TKINTER_AVAILABLE and (modifiers == key.MOD_CTRL + self.mod_offset):
                from pyglet_app_tkinter_dialogs import text_info
                help_win = text_info()
                help_win.run('help', main_help_menu)
            else:
                print main_help_menu

        elif symbol == key.P: # switch between plotting modes
            from pyglet_app_screen_update_elements_static_line import StaticLineUpdateScreen
            from pyglet_app_screen_update_elements_moving_line import MovingLineUpdateScreen

            # we have three different modes currently that we can choose from.
            self._screen_update_mode = (self._screen_update_mode + 1) % 3

            if self._screen_update_mode == 0:
                current_screen = StaticLineUpdateScreen
                mode = 0
            elif self._screen_update_mode == 1: 
                current_screen = StaticLineUpdateScreen
                mode = 1
            elif self._screen_update_mode == 2:
                current_screen = MovingLineUpdateScreen
                mode = None

            self.clearCurrentScreen()
            self.set_current_screen(current_screen)
            self.current_screen.mode = mode
            self.startCurrentScreen()

        elif symbol == key.Q: # show number of elements in plot queue
            print "Plot-Queue size: %d" % (len(self.plot_queue))

        elif symbol == key.S: # take screenshot of current screen content
            if (modifiers == key.MOD_SHIFT + self.mod_offset): # set screenshot path
                label_strg = 'Screenshot path '
                if self.SETTINGS.SCREENSHOT_PATH is not None:
                    label_strg = label_strg + '(currently %s) '%self.SETTINGS.SCREENSHOT_PATH
                got_value, new_value = one_input(self.SETTINGS, label_strg, 'Please provide new Screenshot path and press ENTER: ', 'Screenshot path')
                # nothing given - return.
                if not got_value:
                    return
                # replace '\' with '/' because path.join() transforms everything to '/' notation.
                self.SETTINGS.SCREENSHOT_PATH = new_value.replace('\\', '/')
            elif not (modifiers == key.MOD_CTRL + self.mod_offset):
                try:
                    now = datetime.now().strftime("%Y-%m-%d--%H-%M-%S")
                    filename = 'Screenshot-from-%s---%s.png' %(now, self.PLUGIN_NAME)
                    if self.SETTINGS.SCREENSHOT_PATH is not None:
                        filename = os.path.join(self.SETTINGS.SCREENSHOT_PATH, filename)
                    pyglet.image.get_buffer_manager().get_color_buffer().save(filename)
                    print 'File "%s" saved.' % filename
                except Exception, e:
                    print "An error occurred while saving the screenshot: "
                    print e
                    pass
    def on_key_press(self, symbol, modifiers):

        # offset that needs to be added to 'key.MOD_*' in order to match the
        # 'modifiers' value
        mod_offset = 16
        ''' key press function for y limits '''
        key_matched = self.kpf_change_y_lims(symbol, modifiers, mod_offset)
        # skip remainder of key press function in case 'kpf_change_y_lims' had a hit.
        if key_matched:
            return
        ''' key press function for horizontal line '''
        key_matched = self.kpf_change_horizontal_line(symbol, modifiers,
                                                      mod_offset)
        # skip remainder of key press function in case 'kpf_change_horizontal_line' had a hit.
        if key_matched:
            return
        ''' remaining keys '''
        if symbol == key.A:
            if modifiers == key.MOD_CTRL + mod_offset:
                if self.SHOW_AXES:
                    self.coord_axes, self.y_axis_tics, self.SHOW_AXES = False, False, False
                else:
                    self.SHOW_AXES = True
                    self.coord_axes, self.y_axis_tics = axes_default_with_y_ticks(
                        self.SETTINGS, self.Y_LIMS)

        elif symbol == key.C:
            self.plot_queue = setup_plotting_queue()
            print "Cleared Plot-Queue"

        elif symbol == key.F:  # show / hide FPS display
            self.SHOW_FPS = not self.SHOW_FPS

        elif symbol == key.H:  # show help menu
            print " "
            print "      *** HELP ***"
            print " "
            print "\t 0: \t\t\trestore original y-lims"
            print "\t 1: \t\t\tdecrease upper y-lim"
            print "\t 2: \t\t\tincrease upper y-lim"
            print "\t 3: \t\t\tdecrease lower y-lim"
            print "\t 4: \t\t\tincrease lower y-lim"
            print "\t a + ctrl: \t\tshow / hide axes"
            print "\t f: \t\t\tshow / hide FPS display"
            print "\t q: \t\t\tshow number of elements in plot queue"
            print "\t t: \t\t\tset position of horizontal line"
            print "\t t + shift: \t\tprint out current position of horizontal line"
            print "\t t + ctrl: \t\tshow / hide horizontal line"
            print "\t v + ctrl: \t\tshow / hide vertical line"
            print "\t y: \t\t\tset upper y-lim to value from command line"
            print "\t y + shift: \t\tset lower y-lim to value from command line"
            print "\t y + ctrl: \t\tset upper and lower y limits through GUI"
            print "\t arrow up: \t\tmove horizontal line up by one"
            print "\t arrow down: \t\tmove horizontal line down by one"
            print "\t arrow up + shift: \tmove horizontal line up by five"
            print "\t arrow down + shift: \tmove horizontal line down by five"
            print "\t space bar: \t\tpause / resume screen update"
            print " "

        elif symbol == key.Q:  # show number of elements in plot queue
            print "Plot-Queue size: %d" % (len(self.plot_queue))

        elif symbol == key.V:  # show / hide vertical line (toggle display of vertical line)
            if modifiers == key.MOD_CTRL + mod_offset:
                if not self.SHOW_VERTICAL_LINE:
                    self.line_ver = line_default_vertical(
                        self.SETTINGS.WINDOW_HEIGHT_CURRENT, self.x_coords)
                self.SHOW_VERTICAL_LINE = not self.SHOW_VERTICAL_LINE

        elif symbol == key.ESCAPE:  # quit program
            sys.exit()

        elif symbol == key.SPACE:  # freeze / resume plotting
            self.DO_DRAW = not self.DO_DRAW
    def update(self, dt):

        # update nPointsToUpdate points per `update()` call
        # TODO: handle cases where 'nPoints' is not a multiple of 'nPointsToUpdate'
        # (need to wrap around at the end of the list)
        ''' START  'DATA MANAGEMENT'  '''
        # pick up new data from mmap or other system (i.e. generated)
        new_data, new_data_is_empty, nbr_buffers_per_mmap_file = request_new_data(
            self.USE_MMAP, self.DATA, self.MMAP)

        # don't add empty data to the queue
        # don't use 'NBR_INDEPENDENT_CHANNELS' here, because we might be skipping this channel
        if sum(new_data_is_empty) != len(new_data):
            #print len(new_data[0][0])
            #print new_data[1][0]
            append_data_to_plot_queue(self.plot_queue, new_data,
                                      nbr_buffers_per_mmap_file)
        ''' END  'DATA MANAGEMENT'  '''
        ''' debugging
		if new_data_is_empty[0] == 1:
			print 'new data is empty!'
		else: 
			print ' NOT EMPTY!'

		'''

        # Quit here if we are not supposed to draw anything new. This way the queue
        # keeps growing and we don't miss anything.
        if not self.DO_DRAW:
            return

        # don't purge entire queue - keep at least 'MIN_NBR_BUFFERS_NECESSARY_FOR_UPDATE' elements in queue.
        # this will give us a smoother plotting experience.
        queue_length = len(self.plot_queue)
        if queue_length < MIN_NBR_BUFFERS_NECESSARY_FOR_UPDATE:
            return
        ''' START  'dequeue buffers and prepare them for plotting'  '''
        # plot ALL buffers currently in queue.
        for j in xrange(queue_length):

            # dequeue buffers and update VBOs
            # raw_data is an array of channels containing the data per channel.
            raw_data = get_data_from_plot_queue(self.plot_queue)
            #print raw_data

            # update y values in main VBO - do this for each channel!
            current_pos_in_memory = gl_update_two_coordinates_in_VBO_static_view(
                raw_data, self.vbo_data, self.c, self.nPoints,
                self.nPointsToUpdate, BYTES_PER_POINT, BYTES_PER_COORDINATE,
                self.NBR_CHANNELS, self.x_coords)

            # Update position of vertical line - move it one 'nPointsToUpdate'
            # buffer ahead of currently updated position. calc modulo 'nPoints',
            # so that the position is in the range from 0 to nPoints.
            self.line_ver.curr_pos = (current_pos_in_memory +
                                      self.nPointsToUpdate) % self.nPoints

            # increase counter and modulo 'nPoints', so that 'c' doesn't grow out of bounds.
            self.c = (self.c + 1) % self.nPoints
        ''' END 'dequeue buffers and prepare them for plotting'  '''

        # set the resulting vertical line position.
        if self.SHOW_VERTICAL_LINE:
            self.line_ver.gl_update_line_x_value(self.line_ver.curr_pos)

        # auto-purge plot queue if feature is activated and limit is reached.
        if self.plot_queue_purge_if_size_limit_reached and len(
                self.plot_queue) > self.plot_queue_size_limit:
            self.plot_queue = setup_plotting_queue()
    def setup(self):
        ''' set variables based on init() values. '''
        self.Y_LIMS = [0, self.SETTINGS.WINDOW_HEIGHT_DEFAULT]
        self.SETTINGS.WINDOW_WIDTH_CURRENT = self.SETTINGS.WINDOW_WIDTH_DEFAULT
        self.SETTINGS.WINDOW_HEIGHT_CURRENT = self.SETTINGS.WINDOW_HEIGHT_DEFAULT

        # add 'abs_plugin_ID' to plugin name.
        self.PLUGIN_NAME = self.PLUGIN_NAME + '-' + str(self.abs_plugin_ID)
        ''' setup mmap or random data interface '''
        status, self.MMAP, self.DATA = setup_incoming_data_interface(
            self.USE_MMAP, self.PLUGIN_NAME, self.NBR_CHANNELS,
            self.nPointsToUpdate, self.nPoints,
            self.SETTINGS.WINDOW_WIDTH_CURRENT,
            self.SETTINGS.WINDOW_HEIGHT_CURRENT)
        if not status:
            sys.exit(1)
        ''' setup plot queue '''
        self.plot_queue = setup_plotting_queue()
        ''' generate initial positions & colors, and setup VOBs '''
        self.vbo_data, self.vbo_colors, self.x_coords = \
         gl_setup_initial_data_and_color_and_vbos(self.nPoints, n_COORDINATES_PER_COLOR, self.NBR_CHANNELS, self.SETTINGS.WINDOW_WIDTH_DEFAULT, self.SETTINGS.WINDOW_HEIGHT_DEFAULT)
        ''' horizontal and vertical lines '''
        # horizontal line showing the threshold
        if self.SHOW_HORIZONTAL_LINE:
            self.line_hor = line_default_horizontal(self)

        # vertical line showing which data point is going to be update next
        if self.SHOW_VERTICAL_LINE:
            self.line_ver = line_default_vertical(self)
        ''' axes '''
        if self.SHOW_AXES:
            self.coord_axes, self.y_axis_tics = axes_default_with_y_ticks(self)
        ''' other stuff '''
        # is Tkinter installed and running?
        self.SETTINGS = tkinter_register_with_settings(self.SETTINGS)

        # set default gl modes
        set_gl_defaults(self.POINT_SIZE)

        # try to render a smooth line (if supported by driver)
        gl_enable_line_smoothing()

        # set window title
        win_title = 'generating random data'
        if self.USE_MMAP:
            win_title = 'receiving data from matlab'
        nbr_points_shown = ' -- showing %s points per panel.' % self.nPoints
        self.set_caption(self.PLUGIN_NAME + ' -- ' + win_title +
                         nbr_points_shown)

        # hide mouse - disabled.
        # self.set_mouse_visible(False)

        # schedule the 'update()' method to be called each 'update_interval'
        pyglet.clock.schedule_interval(self.update, self.update_interval)

        # Create a font for our FPS clock
        ft = pyglet.font.load('Arial', 28)
        self.fps_display = pyglet.clock.ClockDisplay(font=ft,
                                                     interval=0.125,
                                                     format='FPS %(fps).2f')
    def on_key_press(self, symbol, modifiers):

        # offset that needs to be added to 'key.MOD_*' in order to match the
        # 'modifiers' value
        mod_offset = 16

        """ key press function for y limits """
        key_matched = self.kpf_change_y_lims(symbol, modifiers, mod_offset)
        # skip remainder of key press function in case 'kpf_change_y_lims' had a hit.
        if key_matched:
            return

        """ key press function for horizontal line """
        key_matched = self.kpf_change_horizontal_line(symbol, modifiers, mod_offset)
        # skip remainder of key press function in case 'kpf_change_horizontal_line' had a hit.
        if key_matched:
            return

        """ remaining keys """
        if symbol == key.A:
            if modifiers == key.MOD_CTRL + mod_offset:
                if self.SHOW_AXES:
                    self.coord_axes, self.y_axis_tics, self.SHOW_AXES = False, False, False
                else:
                    self.SHOW_AXES = True
                    self.coord_axes, self.y_axis_tics = axes_default_with_y_ticks(self.SETTINGS, self.Y_LIMS)

        elif symbol == key.C:
            self.plot_queue = setup_plotting_queue()
            print "Cleared Plot-Queue"

        elif symbol == key.F:  # show / hide FPS display
            self.SHOW_FPS = not self.SHOW_FPS

        elif symbol == key.H:  # show help menu
            print " "
            print "      *** HELP ***"
            print " "
            print "\t 0: \t\t\trestore original y-lims"
            print "\t 1: \t\t\tdecrease upper y-lim"
            print "\t 2: \t\t\tincrease upper y-lim"
            print "\t 3: \t\t\tdecrease lower y-lim"
            print "\t 4: \t\t\tincrease lower y-lim"
            print "\t a + ctrl: \t\tshow / hide axes"
            print "\t f: \t\t\tshow / hide FPS display"
            print "\t q: \t\t\tshow number of elements in plot queue"
            print "\t t: \t\t\tset position of horizontal line"
            print "\t t + shift: \t\tprint out current position of horizontal line"
            print "\t t + ctrl: \t\tshow / hide horizontal line"
            print "\t v + ctrl: \t\tshow / hide vertical line"
            print "\t y: \t\t\tset upper y-lim to value from command line"
            print "\t y + shift: \t\tset lower y-lim to value from command line"
            print "\t y + ctrl: \t\tset upper and lower y limits through GUI"
            print "\t arrow up: \t\tmove horizontal line up by one"
            print "\t arrow down: \t\tmove horizontal line down by one"
            print "\t arrow up + shift: \tmove horizontal line up by five"
            print "\t arrow down + shift: \tmove horizontal line down by five"
            print "\t space bar: \t\tpause / resume screen update"
            print " "

        elif symbol == key.Q:  # show number of elements in plot queue
            print "Plot-Queue size: %d" % (len(self.plot_queue))

        elif symbol == key.V:  # show / hide vertical line (toggle display of vertical line)
            if modifiers == key.MOD_CTRL + mod_offset:
                if not self.SHOW_VERTICAL_LINE:
                    self.line_ver = line_default_vertical(self.SETTINGS.WINDOW_HEIGHT_CURRENT, self.x_coords)
                self.SHOW_VERTICAL_LINE = not self.SHOW_VERTICAL_LINE

        elif symbol == key.ESCAPE:  # quit program
            sys.exit()

        elif symbol == key.SPACE:  # freeze / resume plotting
            self.DO_DRAW = not self.DO_DRAW
    def update(self, dt):

        # update nPointsToUpdate points per `update()` call
        # TODO: handle cases where 'nPoints' is not a multiple of 'nPointsToUpdate'
        # (need to wrap around at the end of the list)

        """ START  'DATA MANAGEMENT'  """
        # pick up new data from mmap or other system (i.e. generated)
        new_data, new_data_is_empty, nbr_buffers_per_mmap_file = request_new_data(self.USE_MMAP, self.DATA, self.MMAP)

        # don't add empty data to the queue
        # don't use 'NBR_INDEPENDENT_CHANNELS' here, because we might be skipping this channel
        if sum(new_data_is_empty) != len(new_data):
            # print len(new_data[0][0])
            # print new_data[1][0]
            append_data_to_plot_queue(self.plot_queue, new_data, nbr_buffers_per_mmap_file)
        """ END  'DATA MANAGEMENT'  """

        """ debugging
		if new_data_is_empty[0] == 1:
			print 'new data is empty!'
		else: 
			print ' NOT EMPTY!'

		"""

        # Quit here if we are not supposed to draw anything new. This way the queue
        # keeps growing and we don't miss anything.
        if not self.DO_DRAW:
            return

            # don't purge entire queue - keep at least 'MIN_NBR_BUFFERS_NECESSARY_FOR_UPDATE' elements in queue.
            # this will give us a smoother plotting experience.
        queue_length = len(self.plot_queue)
        if queue_length < MIN_NBR_BUFFERS_NECESSARY_FOR_UPDATE:
            return

        """ START  'dequeue buffers and prepare them for plotting'  """
        # plot ALL buffers currently in queue.
        for j in xrange(queue_length):

            # dequeue buffers and update VBOs
            # raw_data is an array of channels containing the data per channel.
            raw_data = get_data_from_plot_queue(self.plot_queue)
            # print raw_data

            # update y values in main VBO - do this for each channel!
            current_pos_in_memory = gl_update_two_coordinates_in_VBO_static_view(
                raw_data,
                self.vbo_data,
                self.c,
                self.nPoints,
                self.nPointsToUpdate,
                BYTES_PER_POINT,
                BYTES_PER_COORDINATE,
                self.NBR_CHANNELS,
                self.x_coords,
            )

            # Update position of vertical line - move it one 'nPointsToUpdate'
            # buffer ahead of currently updated position. calc modulo 'nPoints',
            # so that the position is in the range from 0 to nPoints.
            self.line_ver.curr_pos = (current_pos_in_memory + self.nPointsToUpdate) % self.nPoints

            # increase counter and modulo 'nPoints', so that 'c' doesn't grow out of bounds.
            self.c = (self.c + 1) % self.nPoints
        """ END 'dequeue buffers and prepare them for plotting'  """

        # set the resulting vertical line position.
        if self.SHOW_VERTICAL_LINE:
            self.line_ver.gl_update_line_x_value(self.line_ver.curr_pos)

            # auto-purge plot queue if feature is activated and limit is reached.
        if self.plot_queue_purge_if_size_limit_reached and len(self.plot_queue) > self.plot_queue_size_limit:
            self.plot_queue = setup_plotting_queue()
    def setup(self):

        """ set variables based on init() values. """
        self.Y_LIMS = [0, self.SETTINGS.WINDOW_HEIGHT_DEFAULT]
        self.SETTINGS.WINDOW_WIDTH_CURRENT = self.SETTINGS.WINDOW_WIDTH_DEFAULT
        self.SETTINGS.WINDOW_HEIGHT_CURRENT = self.SETTINGS.WINDOW_HEIGHT_DEFAULT

        # add 'abs_plugin_ID' to plugin name.
        self.PLUGIN_NAME = self.PLUGIN_NAME + "-" + str(self.abs_plugin_ID)

        """ setup mmap or random data interface """
        status, self.MMAP, self.DATA = setup_incoming_data_interface(
            self.USE_MMAP,
            self.PLUGIN_NAME,
            self.NBR_CHANNELS,
            self.nPointsToUpdate,
            self.nPoints,
            self.SETTINGS.WINDOW_WIDTH_CURRENT,
            self.SETTINGS.WINDOW_HEIGHT_CURRENT,
        )
        if not status:
            sys.exit(1)

        """ setup plot queue """
        self.plot_queue = setup_plotting_queue()

        """ generate initial positions & colors, and setup VOBs """
        self.vbo_data, self.vbo_colors, self.x_coords = gl_setup_initial_data_and_color_and_vbos(
            self.nPoints,
            n_COORDINATES_PER_COLOR,
            self.NBR_CHANNELS,
            self.SETTINGS.WINDOW_WIDTH_DEFAULT,
            self.SETTINGS.WINDOW_HEIGHT_DEFAULT,
        )

        """ horizontal and vertical lines """
        # horizontal line showing the threshold
        if self.SHOW_HORIZONTAL_LINE:
            self.line_hor = line_default_horizontal(self)

            # vertical line showing which data point is going to be update next
        if self.SHOW_VERTICAL_LINE:
            self.line_ver = line_default_vertical(self)

        """ axes """
        if self.SHOW_AXES:
            self.coord_axes, self.y_axis_tics = axes_default_with_y_ticks(self)

        """ other stuff """
        # is Tkinter installed and running?
        self.SETTINGS = tkinter_register_with_settings(self.SETTINGS)

        # set default gl modes
        set_gl_defaults(self.POINT_SIZE)

        # try to render a smooth line (if supported by driver)
        gl_enable_line_smoothing()

        # set window title
        win_title = "generating random data"
        if self.USE_MMAP:
            win_title = "receiving data from matlab"
        nbr_points_shown = " -- showing %s points per panel." % self.nPoints
        self.set_caption(self.PLUGIN_NAME + " -- " + win_title + nbr_points_shown)

        # hide mouse - disabled.
        # self.set_mouse_visible(False)

        # schedule the 'update()' method to be called each 'update_interval'
        pyglet.clock.schedule_interval(self.update, self.update_interval)

        # Create a font for our FPS clock
        ft = pyglet.font.load("Arial", 28)
        self.fps_display = pyglet.clock.ClockDisplay(font=ft, interval=0.125, format="FPS %(fps).2f")