class Simulation:
    def __init__(self, screen):
        self.state = SimulationState()
        self.state.v = 15
        self.screen = screen
        self.center = screen.size[0] / 2.0
        self.doneSetup = False
        self.quit = False

    def init_state(self):
        self.state.th = 0
        self.state.x = 0
        self.state.z = 0

    def wait_for_key(self, t):
        #event = pygame.event.poll()
        #while event != pygame.NOEVENT:
        #	if event == pygame.KEYDOWN:
        #		self.askForNext.quit = True
        #	event = pygame.event.poll()
        pygame.event.pump()
        if any(pygame.key.get_pressed()):
            print "Got key"
            self.askForNext.parameters.quit = True
        self.askForNext.parameters.enter_go_loop = True

    def update(self, t):

        # Estimate the current frame rate
        try:
            dt = self.frame_timer.get_average_ifi_sec()
        except RuntimeError:
            dt = 0.01

        # Map the pointer position to angular velocity of +/- 90 degrees/s
        curr_pos = pygame.mouse.get_pos()
        self.pos_ring.add(curr_pos[0])
        pos = self.pos_ring.head()
        center = self.center

        self.state.th = self.state.th + dt * (-(math.pi) / 2.0 *
                                              (pos - center) / center)

        # Update steering wheel
        self.wheel.set(angle=-90.0 * (curr_pos[0] - center) / center)

        th = self.state.th
        x = self.state.x
        z = self.state.z

        self.outf.write("%f\t%u\t%u\t%u\t%f\t%f\t%f\n" %
                        (t, curr_pos[0], curr_pos[1], pos, th, x, z))

        # this is a left handed camera transform, the right handed ones that are
        # built in to visionegg were not working for me.
        # Translate, then rotate about the y-axis by our current heading angle
        viewXfrm = numpy.matrix([[math.cos(th), 0.0,
                                  math.sin(th), 0.0], [0.0, 1.0, 0.0, 0.0],
                                 [-math.sin(th), 0.0,
                                  math.cos(th), 0.0],
                                 [
                                     -x * math.cos(th) + z * math.sin(th), 0.0,
                                     -x * math.sin(th) - z * math.cos(th), 1.0
                                 ]])

        # Make a step in the direction of current heading
        self.state.x = x + self.state.v * dt * math.sin(-th)
        self.state.z = z - self.state.v * dt * math.cos(-th)

        self.camera_matrix.parameters.matrix = viewXfrm

    def doSim(self, trial, road, duration, tau, doEyetrack):

        # Measure sample rate in order to calculate delay buffer
        sample_rate = self.screen.measure_refresh_rate(2.0)
        print "Sample rate: " + str(sample_rate)
        #sample_rate = 60

        self.doEyetrack = doEyetrack

        self.pos_ring = RingBuffer(self.center,
                                   int(math.floor(tau * sample_rate)) + 1)
        print("Ring Buffer:: size: " + str(self.pos_ring.size))

        if doEyetrack:
            import pylink
            from EyeLinkCoreGraphicsVE import EyeLinkCoreGraphicsVE

            self.tracker = pylink.EyeLink()
            if self.tracker == None:
                print "Error: Eyelink is not connected"
                sys.exit()

            genv = EyeLinkCoreGraphicsVE(self.screen, self.tracker)
            pylink.openGraphicsEx(genv)

            #Opens the EDF file.
            edfFileName = "TRIAL" + str(trial) + ".EDF"
            self.tracker.openDataFile(edfFileName)

            pylink.flushGetkeyQueue()

            self.tracker.sendCommand("screen_pixel_coords =	0 0 %d %d" %
                                     (VisionEgg.config.VISIONEGG_SCREEN_W,
                                      VisionEgg.config.VISIONEGG_SCREEN_H))

            tracker_software_ver = 0
            eyelink_ver = self.tracker.getTrackerVersion()
            if eyelink_ver == 3:
                tvstr = self.tracker.getTrackerVersionString()
                vindex = tvstr.find("EYELINK CL")
                tracker_software_ver = int(
                    float(tvstr[(vindex + len("EYELINK CL")):].strip()))

            if eyelink_ver >= 2:
                self.tracker.sendCommand("select_parser_configuration 0")
                if eyelink_ver == 2:  #turn off scenelink camera stuff
                    self.tracker.sendCommand("scene_camera_gazemap = NO")
            else:
                self.tracker.sendCommand("saccade_velocity_threshold = 35")
                self.tracker.sendCommand(
                    "saccade_acceleration_threshold = 9500")

            # set EDF file contents
            self.tracker.sendCommand(
                "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON"
            )
            if tracker_software_ver >= 4:
                self.tracker.sendCommand(
                    "file_sample_data	= LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET"
                )
            else:
                self.tracker.sendCommand(
                    "file_sample_data	= LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS")

            # set link data (used for gaze cursor)
            self.tracker.sendCommand(
                "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON")
            if tracker_software_ver >= 4:
                self.tracker.sendCommand(
                    "link_sample_data	= LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET"
                )
            else:
                self.tracker.sendCommand(
                    "link_sample_data	= LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS")

            if not self.doneSetup:
                self.tracker.doTrackerSetup()
                self.doneSetup = True
            else:
                while 1:
                    try:
                        error = self.tracker.doDriftCorrect(
                            self.screen.size[0] / 2, self.screen.size[1] / 2,
                            1, 1)
                        if error != 27:  # ?? from example
                            break
                        else:
                            self.tracker.doTrackerSetup()
                    except:
                        break

        self.screen.parameters.bgcolor = 106.0 / 255.0, 147.0 / 255.0, 0.0
        # Load road data from file and create an image
        roadArray = numpy.loadtxt('road' + str(road) + '.txt')

        # Convert to a Path
        roadPath = ImagePath.Path(
            map(lambda xy: (xy[0], xy[1]), roadArray.tolist()))

        # Use Path to create a plot of the road
        im = Image.new("RGB", (2000, 100), (50, 50, 50))
        draw = ImageDraw.Draw(im)

        # draw each side of the road separately
        draw.line(roadPath[:4000], fill=(200, 200, 200))
        draw.line(roadPath[4000:], fill=(200, 200, 200))

        del draw

        # Lay out a road texture in the x-z plane
        roadTexture = Texture(im)

        del im

        eye_height = 2.5

        vertices = [(-10, -eye_height, 0), (-10, -eye_height, -1000),
                    (10, -eye_height, 0), (10, -eye_height, -1000)]

        rect = TextureStimulus3D(texture=roadTexture,
                                 lowerleft=vertices[0],
                                 lowerright=vertices[1],
                                 upperleft=vertices[2],
                                 upperright=vertices[3])

        # We will use these later for our camera transforms
        self.camera_matrix = ModelView()
        self.frame_timer = FrameTimer()

        self.outf = open(
            'steersim-' + str(trial) + '-' + str(road) + '-out.txt', 'wb')

        # Vewport for the road
        viewport3D = Viewport(
            screen=self.screen,
            projection=SimplePerspectiveProjection(fov_x=75.2),
            camera_matrix=self.camera_matrix,
            stimuli=[rect])

        # Construct a sky
        sky_l = 0
        sky_r = self.screen.size[0]
        sky_t = self.screen.size[1]
        sky_b = self.screen.size[1] / 2

        sky_vertices = [(sky_l, sky_t, 0), (sky_r, sky_t, 0),
                        (sky_r, sky_b, 0), (sky_l, sky_b, 0)]

        sky = Rectangle3D(color=(144.0 / 255.0, 190.0 / 255.0, 1.0),
                          vertex1=sky_vertices[0],
                          vertex2=sky_vertices[1],
                          vertex3=sky_vertices[2],
                          vertex4=sky_vertices[3])

        wheelTexture = Texture('wheel.png')
        self.wheel = TextureStimulus(texture=wheelTexture,
                                     internal_format=gl.GL_RGBA,
                                     position=(self.center, -75),
                                     anchor='center')

        # display the sky in its own viewport
        viewport2D = Viewport(screen=self.screen)
        viewport2D.parameters.stimuli = [sky, self.wheel]

        self.init_state()

        askText = Text(text='Press a key to start',
                       anchor='center',
                       position=(self.center, self.screen.size[1] / 2))
        splash = Viewport(screen=self.screen)
        splash.parameters.stimuli = [askText]
        self.askForNext = Presentation(go_duration=(0.5, 'seconds'),
                                       viewports=[splash])
        self.askForNext.add_controller(
            None, None, FunctionController(during_go_func=self.wait_for_key))
        self.askForNext.parameters.enter_go_loop = True
        self.askForNext.run_forever()

        self.simPres = Presentation(go_duration=(duration, 'seconds'),
                                    viewports=[viewport3D, viewport2D],
                                    handle_event_callbacks=[
                                        (pygame.KEYDOWN, self.check_keypress)
                                    ])
        self.simPres.add_controller(
            None, None, FunctionController(during_go_func=self.update))

        if doEyetrack:
            startTime = pylink.currentTime()
            self.tracker.sendMessage("SYNCTIME %d" %
                                     (pylink.currentTime() - startTime))
            error = self.tracker.startRecording(1, 1, 1, 1)
            self.tracker.sendMessage("PRES %d START" % (trial))

        self.simPres.go()

        if doEyetrack:
            self.tracker.sendMessage("PRES %d END" % (trial))
            self.tracker.stopRecording()

            # File transfer and cleanup!
            self.tracker.setOfflineMode()
            pylink.msecDelay(500)
            #Close the file and transfer it to Display PC
            self.tracker.closeDataFile()
            self.tracker.receiveDataFile(edfFileName, edfFileName)

        self.outf.close()

        if self.quit:
            raise SystemExit

    def check_keypress(self, event):

        if event.key == pygame.K_q:
            self.quit = True
            self.simPres.set(go_duration=(0.0, 'seconds'))
        elif event.key == pygame.K_n:
            self.simPres.set(go_duration=(0.0, 'seconds'))
        elif event.key == pygame.K_UP:
            self.state.v += 1
        elif event.key == pygame.K_DOWN:
            self.state.v -= 1
Beispiel #2
0
        gamma_scale += 0.05
        do_gamma()
    elif event.key in [pygame.locals.K_KP_MINUS, pygame.locals.K_MINUS]:
        gamma_scale -= 0.05
        do_gamma()


def do_gamma():
    global gamma_scale, text2
    r = (np.arange(256) * 256 * gamma_scale).astype('i')
    g = r
    b = r
    worked = pygame.display.set_gamma_ramp(r, g, b)
    if worked:
        text2.parameters.text = "set_gamma_ramp(r,g,b): success"
    else:
        text2.parameters.text = "set_gamma_ramp(r,g,b): failure"


do_gamma()  # set gamma once initially

handle_event_callbacks = [(pygame.locals.QUIT, quit),
                          (pygame.locals.KEYDOWN, keydown)]

# Create an instance of the Presentation class
p = Presentation(viewports=[viewport],
                 handle_event_callbacks=handle_event_callbacks)

# Go!
p.run_forever()
Beispiel #3
0
class VisionEggView(object):
    """ This class handles VisionEgg internals and the creation of
    common/standard stimuli like centered words, a fixation cross or
    a countdown. Inherit this and pass the type to VisionEggFeedback
    for customization.
    """
    def __init__(self):
        self.__init_attributes()

    def __init_attributes(self):
        """ Setup internal attributes. """
        self._logger = logging.getLogger('VisionEggView')
        self._logger.addHandler(logging.FileHandler('log'))
        self._screen_acquired = False
        self._viewports = []

    def set_trigger_function(self, trigger):
        self._trigger = trigger

    def set_event_handlers(self, event_handlers):
        """ Set pygame/VisionEgg event handler function. """
        self._event_handlers = event_handlers

    def set_iterator_semaphore(self, flag):
        """ Specify the object to be used as semaphore for iterators.
        See L{Switcherator} for more.
        """
        self._iter = lambda it: Switcherator(flag, it)

    def update_parameters(self, **kwargs):
        """ Apply new parameters set from pyff. """
        for k, v in kwargs.iteritems():
            setattr(self, '_' + k, v)
        if self._screen_acquired:
            self.reinit()

    def acquire(self):
        """ Allow L{update_parameters} initialize VisionEgg. """
        self._screen_acquired = True

    def reinit(self):
        """ Initialize VisionEgg objects. """
        self.__init_screen()
        self.__init_presentation()
        self.__init_viewports()
        self.init()
        self.__init_text()

    def init(self):
        """ Overload this for additional custom VisionEgg
        initialization.
        """
        pass

    def __init_screen(self):
        """ Create the VisionEgg Screen object using the pyff
        configuration parameters 'fullscreen' and 'geometry' and the
        font and background colors according to parameters
        'font_color_name' and 'bg_color'.
        """
        params = {'fullscreen': self._fullscreen, 'sync_swap': True}
        if not self._fullscreen:
            os.environ['SDL_VIDEO_WINDOW_POS'] = '%d, %d' % (self._geometry[0],
                                                             self._geometry[1])
            params['size'] = self._geometry[2:]
        self.screen = Screen(**params)
        self._set_bg_color()
        self._set_font_color()

    def __init_presentation(self):
        """ Provide a standard presentation object. """
        self.presentation = Presentation(
            handle_event_callbacks=self._event_handlers)

    def __init_viewports(self):
        """ Provide a standard viewport. """
        self._standard_viewport = Viewport(screen=self.screen)
        self.add_viewport(self._standard_viewport)

    def __init_text(self):
        """ Provide a text in the screen center for standard stimuli and
        fixation cross etc.
        """
        sz = self.screen.size
        self._center_text = self.add_color_word(position=(sz[0] / 2.,
                                                          sz[1] / 2.),
                                                font_size=self._font_size)

    def add_viewport(self, viewport):
        """ Add an additional custom viewport object to the list of
        viewports.
        """
        self._viewports.append(viewport)
        self.presentation.set(viewports=self._viewports)

    def clear_stimuli(self):
        """ Remove all existing stimuli in the standard viewport. """
        self.set_stimuli()

    def add_stimuli(self, *stimuli):
        """ Add additional custom stimulus objects to the list of
        stimuli. TextList instances need their own Viewport, as they
        consist of multiple stimulus objects that are deleted everytime
        they change, and so the Viewport needs to have a reference to
        the containing TextList, otherwise they get lost.
        """
        text_lists = filter(lambda s: isinstance(s, TextList), stimuli)
        if text_lists:
            for text in text_lists:
                self.add_viewport(Viewport(screen=self.screen, stimuli=text))
            stimuli = filter(lambda s: not isinstance(s, TextList), stimuli)
        stimuli = self._standard_viewport.parameters.stimuli + list(stimuli)
        if stimuli:
            self.set_stimuli(*stimuli)

    def set_stimuli(self, *stimuli):
        """ Set the list of stimulus objects.  """
        self._standard_viewport.set(stimuli=list(stimuli))

    def add_text_stimulus(self, text, font_size=None, **kw):
        if not kw.has_key('anchor'):
            kw['anchor'] = 'center'
        font_size = font_size or self._font_size
        txt = VisionEgg.Text.Text(text=text, font_size=font_size, **kw)
        self.add_stimuli(txt)
        return txt

    def add_color_word(self, text='', font_size=None, **kw):
        font_size = font_size or self._font_size
        txt = ColorWord(text=text, symbol_size=font_size, **kw)
        self.add_stimuli(txt)
        return txt

    def add_image_stimulus(self, **kw):
        if not kw.has_key('anchor'):
            kw['anchor'] = 'center'
        img = TextureStimulus(**kw)
        self.add_stimuli(img)
        return img

    def _create_color(self, name):
        try:
            if isinstance(name, tuple):
                return Color(*name).normalize()
            else:
                return Color(str(name)).normalize()
        except ValueError:
            self._logger.warn('No such pygame.Color: %s' % str(name))

    def _set_font_color(self):
        """ Set the standard font color by pygame name. """
        self._font_color = (self._create_color(self._font_color_name)
                            or Color(1, 1, 1, 255).normalize())

    def _set_bg_color(self):
        """ Set the standard background color by pygame name. """
        c = (self._create_color(self._bg_color)
             or Color(0, 0, 0, 255).normalize())
        self.screen.set(bgcolor=c)

    def present_frames(self, num_frames):
        """ Launch the presentation main loop for a given number of
        frames.
        """
        self.presentation.set(go_duration=(num_frames, 'frames'))
        self.presentation.go()

    def present(self, sec):
        self.presentation.set(go_duration=(sec, 'seconds'))
        self.presentation.go()

    def update(self):
        """ Repaint the canvas for one frame to update changed stimuli.
        """
        self.present_frames(1)

    def center_word(self, text, color=None):
        """ Set the standard word in the screen center. """
        self._center_text.set(text=text)
        self._center_text.set(colors=color or (self._font_color
                                               for l in self._center_text))

    def clear_center_word(self):
        """ Remove the center word from the screen. """
        self.center_word('')
        self.update()

    def present_center_word(self, text, seconds, color=None):
        self.center_word(text, color)
        self.present(seconds)
        self.clear_center_word()

    def ask(self, question=True):
        """ Loop indefinitely until answered() is called. If question is
        True, a question mark is shown in the center.
        """
        if question:
            self.center_word('?')
        self.presentation.run_forever()
        self.presentation.set(quit=False)
        self.clear_center_word()

    def answered(self):
        """ Abort the current presentation (usually the question mark)
        after subject input. For thread safety, the screen shouldn't be
        changed here.
        """
        self.presentation.set(quit=True)

    def show_fixation_cross(self):
        """ Display the pyff parameter 'fixation_cross_symbol' for the
        period of time given by pyff parameter 'fixation_cross_time'.
        """
        self.center_word(self._fixation_cross_symbol)
        self._trigger(marker.FIXATION_START, wait=True)
        self.present(self._fixation_cross_time)
        self._trigger(marker.FIXATION_END, wait=True)

    def countdown(self):
        """ Display a countdown according to pyff parameters
        'countdown_start' and 'countdown_symbol_duration'.
        """
        self._trigger(marker.COUNTDOWN_START, wait=True)
        for i in self._iter(reversed(xrange(self._countdown_start + 1))):
            self.center_word(str(i))
            self.present(self._countdown_symbol_duration)
        self._trigger(marker.COUNTDOWN_END, wait=True)
        self.clear_center_word()

    def close(self):
        """ Shut down the screen. """
        self._screen_acquired = False
        self.screen.close()

    def quit(self):
        """ Stop the presentation. """
        self.presentation.set(quit=True)
        self.presentation.set(go_duration=(1, 'frames'))
Beispiel #4
0
import VisionEgg
VisionEgg.start_default_logging(); VisionEgg.watch_exceptions()

from VisionEgg.Core import *
from VisionEgg.FlowControl import Presentation
from VisionEgg.Gratings import *
from VisionEgg.PyroHelpers import *

pyro_server = PyroServer()

# get visionegg stimulus ready to go
screen = get_default_screen()
stimulus = SinGrating2D(temporal_freq_hz=0.0)
viewport = Viewport(screen=screen,stimuli=[stimulus])
p = Presentation(go_duration=(5.0,'seconds'),viewports=[viewport])

# make a controller, serve it via pyro, and glue it to the Presentation
tf_controller = PyroConstantController(during_go_value=0.0)
pyro_server.connect(tf_controller,'tf_controller')
p.add_controller(stimulus,'temporal_freq_hz', tf_controller)

quit_controller = PyroConstantController(during_go_value=0)
pyro_server.connect(quit_controller,'quit_controller')
p.add_controller(p,'quit', quit_controller)

# get listener controller and register it
p.add_controller(None,None, pyro_server.create_listener_controller())

# initialize graphics to between presentations state
p.run_forever()
Beispiel #5
0
class VisionEggView(object):
    """ This class handles VisionEgg internals and the creation of
    common/standard stimuli like centered words, a fixation cross or
    a countdown. Inherit this and pass the type to VisionEggFeedback
    for customization.
    """
    def __init__(self):
        self.__init_attributes()

    def __init_attributes(self):
        """ Setup internal attributes. """
        self._logger = logging.getLogger('VisionEggView')
        self._logger.addHandler(logging.FileHandler('log'))
        self._screen_acquired = False
        self._viewports = []

    def set_trigger_function(self, trigger):
        self._trigger = trigger

    def set_event_handlers(self, event_handlers):
        """ Set pygame/VisionEgg event handler function. """
        self._event_handlers = event_handlers

    def set_iterator_semaphore(self, flag):
        """ Specify the object to be used as semaphore for iterators.
        See L{Switcherator} for more.
        """
        self._iter = lambda it: Switcherator(flag, it)

    def update_parameters(self, **kwargs):
        """ Apply new parameters set from pyff. """
        for k, v in kwargs.iteritems():
            setattr(self, '_' + k, v)
        if self._screen_acquired:
            self.reinit()

    def acquire(self):
        """ Allow L{update_parameters} initialize VisionEgg. """
        self._screen_acquired = True

    def reinit(self):
        """ Initialize VisionEgg objects. """
        self.__init_screen()
        self.__init_presentation()
        self.__init_viewports()
        self.init()
        self.__init_text()

    def init(self):
        """ Overload this for additional custom VisionEgg
        initialization.
        """
        pass

    def __init_screen(self):
        """ Create the VisionEgg Screen object using the pyff
        configuration parameters 'fullscreen' and 'geometry' and the
        font and background colors according to parameters
        'font_color_name' and 'bg_color'.
        """
        params = { 'fullscreen': self._fullscreen, 'sync_swap': True }
        if not self._fullscreen:
            os.environ['SDL_VIDEO_WINDOW_POS'] = '%d, %d' % (self._geometry[0],
                                                            self._geometry[1])
            params['size'] = self._geometry[2:]
        self.screen = Screen(**params)
        self._set_bg_color()
        self._set_font_color()

    def __init_presentation(self):
        """ Provide a standard presentation object. """
        self.presentation = Presentation(handle_event_callbacks=
                                         self._event_handlers)

    def __init_viewports(self):
        """ Provide a standard viewport. """
        self._standard_viewport = Viewport(screen=self.screen)
        self.add_viewport(self._standard_viewport)

    def __init_text(self):
        """ Provide a text in the screen center for standard stimuli and
        fixation cross etc.
        """
        sz = self.screen.size
        self._center_text = self.add_color_word(position=(sz[0] / 2.,
                                                          sz[1] / 2.),
                                                font_size=self._font_size)

    def add_viewport(self, viewport):
        """ Add an additional custom viewport object to the list of
        viewports.
        """
        self._viewports.append(viewport)
        self.presentation.set(viewports=self._viewports)

    def clear_stimuli(self):
        """ Remove all existing stimuli in the standard viewport. """
        self.set_stimuli()

    def add_stimuli(self, *stimuli):
        """ Add additional custom stimulus objects to the list of
        stimuli. TextList instances need their own Viewport, as they
        consist of multiple stimulus objects that are deleted everytime
        they change, and so the Viewport needs to have a reference to
        the containing TextList, otherwise they get lost.
        """
        text_lists = filter(lambda s: isinstance(s, TextList), stimuli)
        if text_lists:
            for text in text_lists:
                self.add_viewport(Viewport(screen=self.screen, stimuli=text))
            stimuli = filter(lambda s: not isinstance(s, TextList), stimuli)
        stimuli = self._standard_viewport.parameters.stimuli + list(stimuli)
        if stimuli:
            self.set_stimuli(*stimuli)

    def set_stimuli(self, *stimuli):
        """ Set the list of stimulus objects.  """
        self._standard_viewport.set(stimuli=list(stimuli))

    def add_text_stimulus(self, text, font_size=None, **kw):
        if not kw.has_key('anchor'):
            kw['anchor'] = 'center'
        font_size = font_size or self._font_size
        txt = VisionEgg.Text.Text(text=text, font_size=font_size, **kw)
        self.add_stimuli(txt)
        return txt

    def add_color_word(self, text='', font_size=None, **kw):
        font_size = font_size or self._font_size
        txt = ColorWord(text=text, symbol_size=font_size, **kw)
        self.add_stimuli(txt)
        return txt

    def add_image_stimulus(self, **kw):
        if not kw.has_key('anchor'):
            kw['anchor'] = 'center'
        img = TextureStimulus(**kw)
        self.add_stimuli(img)
        return img

    def _create_color(self, name):
        try:
            if isinstance(name, tuple):
                return Color(*name).normalize()
            else:
                return Color(str(name)).normalize()
        except ValueError:
            self._logger.warn('No such pygame.Color: %s' % str(name))

    def _set_font_color(self):
        """ Set the standard font color by pygame name. """
        self._font_color = (self._create_color(self._font_color_name) or
                            Color(1, 1, 1, 255).normalize())

    def _set_bg_color(self):
        """ Set the standard background color by pygame name. """
        c = (self._create_color(self._bg_color) or
             Color(0, 0, 0, 255).normalize())
        self.screen.set(bgcolor=c)

    def present_frames(self, num_frames):
        """ Launch the presentation main loop for a given number of
        frames.
        """
        self.presentation.set(go_duration=(num_frames, 'frames'))
        self.presentation.go()

    def present(self, sec):
        self.presentation.set(go_duration=(sec, 'seconds'))
        self.presentation.go()

    def update(self):
        """ Repaint the canvas for one frame to update changed stimuli.
        """
        self.present_frames(1)

    def center_word(self, text, color=None):
        """ Set the standard word in the screen center. """
        self._center_text.set(text=text)
        self._center_text.set(colors=color or (self._font_color for l in
                                           self._center_text))

    def clear_center_word(self):
        """ Remove the center word from the screen. """
        self.center_word('')
        self.update()

    def present_center_word(self, text, seconds, color=None):
        self.center_word(text, color)
        self.present(seconds)
        self.clear_center_word()

    def ask(self, question=True):
        """ Loop indefinitely until answered() is called. If question is
        True, a question mark is shown in the center.
        """
        if question:
            self.center_word('?')
        self.presentation.run_forever()
        self.presentation.set(quit=False)
        self.clear_center_word()

    def answered(self):
        """ Abort the current presentation (usually the question mark)
        after subject input. For thread safety, the screen shouldn't be
        changed here.
        """
        self.presentation.set(quit=True)

    def show_fixation_cross(self):
        """ Display the pyff parameter 'fixation_cross_symbol' for the
        period of time given by pyff parameter 'fixation_cross_time'.
        """
        self.center_word(self._fixation_cross_symbol)
        self._trigger(marker.FIXATION_START, wait=True)
        self.present(self._fixation_cross_time)
        self._trigger(marker.FIXATION_END, wait=True)

    def countdown(self):
        """ Display a countdown according to pyff parameters
        'countdown_start' and 'countdown_symbol_duration'.
        """
        self._trigger(marker.COUNTDOWN_START, wait=True)
        for i in self._iter(reversed(xrange(self._countdown_start + 1))):
            self.center_word(str(i))
            self.present(self._countdown_symbol_duration)
        self._trigger(marker.COUNTDOWN_END, wait=True)
        self.clear_center_word()

    def close(self):
        """ Shut down the screen. """
        self._screen_acquired = False
        self.screen.close()

    def quit(self):
        """ Stop the presentation. """
        self.presentation.set(quit=True)
        self.presentation.set(go_duration=(1, 'frames'))