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
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()
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'))
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()
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'))