示例#1
0
def stimDisplayMirrorChildFunction(qTo,
                                   qFrom,
                                   windowSize=[1920 / 2, 1080 / 2],
                                   windowPosition=[0, 0]):
    import sdl2
    import sdl2.ext
    import sys
    import time
    from PIL import Image  #for image manipulation
    try:
        import appnope
        appnope.nope()
    except:
        pass

    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    window = sdl2.ext.Window("mirror",
                             size=windowSize,
                             position=windowPosition,
                             flags=sdl2.SDL_WINDOW_SHOWN)
    windowID = sdl2.SDL_GetWindowID(window.window)
    windowSurf = sdl2.SDL_GetWindowSurface(window.window)
    windowArray = sdl2.ext.pixels3d(windowSurf.contents)

    sdl2.ext.fill(windowSurf.contents,
                  sdl2.pixels.SDL_Color(r=255, g=255, b=255, a=255))
    window.refresh()

    for i in range(10):
        sdl2.SDL_PumpEvents()  #to show the windows

    def exitSafely():
        sys.exit()

    while True:
        if not qTo.empty():
            message = qTo.get()
            if message == 'quit':
                exitSafely()
            elif message[0] == 'frame':
                # print ['q',time.time()-message[3]] #time spent in queue
                res = message[1]
                buffer = message[2]
                image = Image.fromstring(mode="RGB", size=res, data=buffer)
                image = image.transpose(Image.ROTATE_270)
                # start = time.time()
                # image.thumbnail([res[1]/2,res[0]/2],Image.LANCZOS)
                # print ['resize',time.time()-start]
                windowArray[:, :, 0:3] = image
                window.refresh()
        sdl2.SDL_PumpEvents()
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_WINDOWEVENT:
                if (event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE):
                    exitSafely()
示例#2
0
def writerChildFunction(qTo,
                        qFrom,
                        windowSize=[200, 200],
                        windowPosition=[0, 0]):
    import sdl2
    import sdl2.ext
    import sys
    import time
    try:
        import appnope
        appnope.nope()
    except:
        pass

    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    window = sdl2.ext.Window("writer",
                             size=windowSize,
                             position=windowPosition,
                             flags=sdl2.SDL_WINDOW_SHOWN)
    windowID = sdl2.SDL_GetWindowID(window.window)
    windowSurf = sdl2.SDL_GetWindowSurface(window.window)
    sdl2.ext.fill(windowSurf.contents,
                  sdl2.pixels.SDL_Color(r=255, g=255, b=255, a=255))
    window.refresh()

    for i in range(10):
        sdl2.SDL_PumpEvents()  #to show the windows

    files = {}

    def exitSafely():
        try:
            for index, fileObj in files.items():
                fileObj.close()
                # gpg -r "Michael Lawrence <*****@*****.**>" -e mac.txt
        except:
            pass
        sys.exit()

    while True:
        if not qTo.empty():
            message = qTo.get()
            if message == 'quit':
                exitSafely()
            elif message[0] == 'newFile':
                files[message[1]] = open(message[2], 'w')
            elif message[0] == 'write':
                files[message[1]].write(message[2] + '\n')
        else:
            time.sleep(1)
        sdl2.SDL_PumpEvents()
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_WINDOWEVENT:
                if (event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE):
                    exitSafely()
示例#3
0
    async def run_async(self):
        self.running = True
        self.startup()

        def event_handler(data, event_ptr):
            if self.running:
                # SDL2 seems to re-use SDL_Event structures, so we need to make a copy.
                event = sdl2.SDL_Event()
                ctypes.pointer(event)[0] = event_ptr.contents
                self.dispatch(event)
            return 0

        watcher = sdl2.SDL_EventFilter(event_handler)
        sdl2.SDL_AddEventWatch(watcher, None)

        loop = asyncio.get_running_loop()

        fps = 60.0
        frame_time = 1.0 / fps
        last_tick = loop.time()
        while self.running:
            sdl2.SDL_PumpEvents()
            # dt here will be how much time since the last loop minus any event handling.
            dt = loop.time() - last_tick
            await asyncio.sleep(max(0, frame_time - dt))
            # dt here will be how much time since the last call to tick.
            dt = loop.time() - last_tick
            self.tick(dt)
            last_tick = loop.time()

        sdl2.SDL_DelEventWatch(watcher, None)
        self.cleanup()
        sdl2.SDL_Quit()
示例#4
0
def getBrakeVal():
    sdl2.SDL_PumpEvents()
    joy_y = sdl2.SDL_JoystickGetAxis(joystick, 1)
    joy_y = (joy_y / 32767)
    if (joy_y < 0.001):
        joy_y = 0
    return joy_y
示例#5
0
 def __init__(self, stimDisplayRes,
              stimDisplayPosition):  #,stimDisplayMirrorChild):
     self.stimDisplayRes = stimDisplayRes
     # self.stimDisplayMirrorChild = stimDisplayMirrorChild
     sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
     self.stimDisplayRes = stimDisplayRes
     self.stimDisplayPosition = stimDisplayPosition
     self.Window = sdl2.video.SDL_CreateWindow(
         byteify('stimDisplay', "utf-8"), self.stimDisplayPosition[0],
         self.stimDisplayPosition[1], self.stimDisplayRes[0],
         self.stimDisplayRes[1],
         sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_SHOWN
         | sdl2.SDL_RENDERER_ACCELERATED | sdl2.SDL_RENDERER_PRESENTVSYNC)
     self.glContext = sdl2.SDL_GL_CreateContext(self.Window)
     gl.glMatrixMode(gl.GL_PROJECTION)
     gl.glLoadIdentity()
     gl.glOrtho(0, stimDisplayRes[0], stimDisplayRes[1], 0, 0, 1)
     gl.glMatrixMode(gl.GL_MODELVIEW)
     gl.glDisable(gl.GL_DEPTH_TEST)
     gl.glReadBuffer(gl.GL_FRONT)
     gl.glClearColor(0, 0, 0, 1)
     start = time.time()
     while time.time() < (start + 2):
         sdl2.SDL_PumpEvents()
     self.refresh()
     self.refresh()
def ss_thread(q, stop_event):
    """q is a Queue object, stop_event is an Event.
  stop_event from http://stackoverflow.com/questions/6524459/stopping-a-thread-python
  """
    while (not stop_event.is_set()):
        if q.empty():
            sdl2.SDL_PumpEvents()
            q.put((getScreenShot(), getJoystickState(globalJoystickInput)))
示例#7
0
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()

        sdl2.SDL_PumpEvents()
        output = globalJoystickInput.getJoystickState()
        output_json = getJoystickJson(output) 
        if(__name__ == '__main__'):
            print(output_json)

        self.wfile.write(str.encode(output_json))
        return
def get_gamepad_state(gp):
    # update joystick info
    sdl2.SDL_PumpEvents()
    gp_state = {}

    for stick in gp['sticks']:
        gp_state[stick] = scaled_stick_value(gp, gp['sticks'][stick]['id'], gp['sticks'][stick]['invert'])

    for btn in gp['btns']:
        gp_state[btn] = sdl2.SDL_JoystickGetButton(gp['gp_object'], gp['btns'][btn])
        # This way a pressed button outputs a number equivalent
        # to a fully bent stick
    # print(gp_state)
    return gp_state
示例#9
0
    def steer(self):
        angle = self.state.angle
        dist = self.state.trackPos

        steer = (angle - dist * 0.5) / self.steer_lock
        self.control.setSteer(steer)

        sdl2.SDL_PumpEvents()
        wheel = sdl2.SDL_JoystickGetAxis(self.joystick, 0)
        wheel = -wheel / 32767.0

        #print steer, wheel, steer-wheel

        self.generate_force(steer - wheel)
示例#10
0
 def waitForResponse():
     # sdl2.SDL_FlushEvents()
     done = False
     while not done:
         sdl2.SDL_PumpEvents()
         for event in sdl2.ext.get_events():
             if event.type == sdl2.SDL_KEYDOWN:
                 response = sdl2.SDL_GetKeyName(
                     event.key.keysym.sym).lower()
                 if response == 'escape':
                     exitSafely()
                 else:
                     done = True
     # sdl2.SDL_FlushEvents()
     return response
def get_gamepad_state(gp):
    # update joystick info
    sdl2.SDL_PumpEvents()
    gp_state = {}

    for stick in gp['sticks']:
        gp_state[stick] = scaled_stick_value(gp, gp['sticks'][stick]['id'], gp['sticks'][stick]['invert'])

    for btn in gp['btns']:
        gp_state[btn] = sdl2.SDL_JoystickGetButton(gp['gp_object'], gp['btns'][btn])
        #this way a pressed button outputs a number equivalent to a fully bent stick

    if OCULUS_ENABLED:
        gp_state['look_h'] = int(Y_AXIS * 10)  # scaled_stick_value(gp,2,stick_max=300),
        gp_state['look_v'] = int(X_AXIS * -1.9)  # scaled_stick_value(gp,3) * gp['invert_y'],

    return gp_state
示例#12
0
    def read(self):
        """Read all the sticks and switches"""

        # Force an update of the joystick channels
        sdl2.SDL_PumpEvents()

        # Ensure that the Tx is connected
        if sdl2.SDL_NumJoysticks() == 0:
            if self.joystick:
                sdl2.SDL_JoystickClose(self.joystick)
                self.joystick = None
            return False
        elif not self.joystick:
            # Open the first joystick if necessary
            self.joystick = sdl2.SDL_JoystickOpen(0)

        # Read all the channels
        ret = []
        for channel in range(self.channels):
            val = sdl2.SDL_JoystickGetAxis(self.joystick, channel)
            ret.append(int(((val / 65536.0) + 0.5) * 800.0 + 1100.0))

        # Return the list of values
        return ret
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()

        sdl2.SDL_PumpEvents()
        joystick_state = globalJoystickInput.getJoystickState()
        global globalInputOverride, globalInProcessOfOverride

        if (joystick_state[12] == 1 and joystick_state[13] == 1
                and not globalInProcessOfOverride):
            globalInputOverride = not globalInputOverride
            print('inputOverride:', globalInputOverride)
            globalInProcessOfOverride = True
        elif (globalInProcessOfOverride):
            globalInProcessOfOverride = (joystick_state[12] == 1
                                         and joystick_state[13] == 1)

        if not globalInputOverride:
            #AI input
            if (not workerQueue.empty()):
                global globalOutputJson
                globalOutputJson = workerQueue.get()

            print(globalOutputJson)

            self.wfile.write(str.encode(globalOutputJson))

        else:
            #controller input
            output_json = getJoystickJson(joystick_state)
            print(output_json)

            self.wfile.write(str.encode(output_json))

        return
示例#14
0
def calibrationChildFunction(qTo,
                             qFrom,
                             viewingDistance=100,
                             stimDisplayWidth=100,
                             stimDisplayRes=(2560, 1440),
                             stimDisplayPosition=(-2560, 0),
                             mirrorDisplayPosition=(0, 0),
                             calibrationDotSizeInDegrees=1,
                             timestampMethod=0,
                             mirrorDownSize=2,
                             manualCalibrationOrder=True):
    import numpy  #for image and display manipulation
    import scipy.misc  #for image and display manipulation
    import math  #for trig and other math stuff
    import sys  #for quitting
    import sdl2
    import sdl2.ext
    import random

    #set the getTime function
    if (timestampMethod == 0) or (timestampMethod == 1):
        #initialize timer
        sdl2.SDL_Init(sdl2.SDL_INIT_TIMER)
        if timestampMethod == 0:
            #define a function to use the high-precision timer, returning a float in seconds
            def getTime():
                return sdl2.SDL_GetPerformanceCounter(
                ) * 1.0 / sdl2.SDL_GetPerformanceFrequency()

        elif timestampMethod == 1:
            #use the SDL_GetTicks timer
            def getTime():
                return sdl2.SDL_GetTicks() / 1000.0
    elif timestampMethod == 2:
        #use time.time()
        import time
        getTime = time.time

    #initialize video
    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    sdl2.SDL_SetHint("SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0")
    mirrorDisplay = sdl2.ext.Window("Mirror",
                                    size=(stimDisplayRes[0] / mirrorDownSize,
                                          stimDisplayRes[1] / mirrorDownSize),
                                    position=mirrorDisplayPosition,
                                    flags=sdl2.SDL_WINDOW_SHOWN)
    mirrorDisplaySurf = sdl2.SDL_GetWindowSurface(mirrorDisplay.window)
    mirrorDisplayArray = sdl2.ext.pixels3d(mirrorDisplaySurf.contents)
    # stimDisplay = sdl2.ext.Window("Calibration",size=stimDisplayRes,position=stimDisplayPosition,flags=sdl2.SDL_WINDOW_SHOWN|sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP|sdl2.SDL_RENDERER_ACCELERATED | sdl2.SDL_RENDERER_PRESENTVSYNC)
    stimDisplay = sdl2.ext.Window(
        "Calibration",
        size=stimDisplayRes,
        position=stimDisplayPosition,
        flags=sdl2.SDL_WINDOW_SHOWN | sdl2.SDL_WINDOW_BORDERLESS
        | sdl2.SDL_RENDERER_ACCELERATED | sdl2.SDL_RENDERER_PRESENTVSYNC)
    stimDisplaySurf = sdl2.SDL_GetWindowSurface(stimDisplay.window)
    stimDisplayArray = sdl2.ext.pixels3d(stimDisplaySurf.contents)
    sdl2.SDL_PumpEvents()  #to show the windows
    sdl2.SDL_PumpEvents()  #to show the windows
    sdl2.SDL_PumpEvents()  #to show the windows
    sdl2.SDL_PumpEvents()  #to show the windows
    sdl2.SDL_PumpEvents()  #to show the windows
    sdl2.SDL_PumpEvents()  #to show the windows
    ########
    #Perform some calculations to convert stimulus measurements in degrees to pixels
    ########
    stimDisplayWidthInDegrees = math.degrees(
        math.atan((stimDisplayWidth / 2.0) / viewingDistance) * 2)
    PPD = stimDisplayRes[
        0] / stimDisplayWidthInDegrees  #compute the pixels per degree (PPD)
    calibrationDotSize = int(calibrationDotSizeInDegrees * PPD)
    #initialize font
    sdl2.sdlttf.TTF_Init()
    font = sdl2.sdlttf.TTF_OpenFont('./pytracker/Resources/DejaVuSans.ttf',
                                    int(PPD) * 2)
    ########
    # Define some useful colors for SDL2
    ########
    white = sdl2.pixels.SDL_Color(r=255, g=255, b=255, a=255)
    black = sdl2.pixels.SDL_Color(r=0, g=0, b=0, a=255)
    grey = sdl2.pixels.SDL_Color(r=127, g=127, b=127, a=255)
    lightGrey = sdl2.pixels.SDL_Color(r=200, g=200, b=200, a=255)

    def drawDot(loc):
        cy, cx = loc
        cx = stimDisplayRes[1] / 2 + cx
        cy = stimDisplayRes[0] / 2 + cy
        radius = calibrationDotSize / 2
        y, x = numpy.ogrid[-radius:radius, -radius:radius]
        index = numpy.logical_and((x**2 + y**2) <= (radius**2),
                                  (x**2 + y**2) >= ((radius / 4)**2))
        stimDisplayArray[(cy - radius):(cy + radius),
                         (cx - radius):(cx + radius), ][index] = [
                             255, 255, 255, 255
                         ]

    calibrationLocations = dict()
    calibrationLocations['CENTER'] = numpy.array([0, 0])
    calibrationLocations['N'] = numpy.array(
        [0, int(0 - stimDisplayRes[1] / 2.0 + calibrationDotSize)])
    calibrationLocations['S'] = numpy.array(
        [0, int(0 + stimDisplayRes[1] / 2.0 - calibrationDotSize)])
    calibrationLocations['E'] = numpy.array(
        [int(0 - stimDisplayRes[0] / 2.0 + calibrationDotSize), 0])
    calibrationLocations['W'] = numpy.array(
        [int(0 + stimDisplayRes[0] / 2.0 - calibrationDotSize), 0])
    calibrationLocations['NE'] = numpy.array([
        int(0 + stimDisplayRes[0] / 2.0 - calibrationDotSize),
        int(0 - stimDisplayRes[1] / 2.0 + calibrationDotSize)
    ])
    calibrationLocations['SE'] = numpy.array([
        int(0 + stimDisplayRes[0] / 2.0 - calibrationDotSize),
        int(0 + stimDisplayRes[1] / 2.0 - calibrationDotSize)
    ])
    calibrationLocations['NW'] = numpy.array([
        int(0 - stimDisplayRes[0] / 2.0 + calibrationDotSize),
        int(0 - stimDisplayRes[1] / 2.0 + calibrationDotSize)
    ])
    calibrationLocations['SW'] = numpy.array([
        int(0 - stimDisplayRes[0] / 2.0 + calibrationDotSize),
        int(0 + stimDisplayRes[1] / 2.0 - calibrationDotSize)
    ])
    calibrationKey = {
        'q': 'NW',
        'w': 'N',
        'e': 'NE',
        'a': 'E',
        's': 'CENTER',
        'd': 'W',
        'z': 'SW',
        'x': 'S',
        'c': 'SE'
    }

    # calibrationLocations['N2'] = numpy.array([0,int((0-stimDisplayRes[1]/2.0+calibrationDotSize)/2.0)])
    # calibrationLocations['S2'] = numpy.array([0,int((0+stimDisplayRes[1]/2.0-calibrationDotSize)/2.0)])
    # calibrationLocations['W2'] = numpy.array([int((0-stimDisplayRes[0]/2.0+calibrationDotSize)/2.0),0])
    # calibrationLocations['E2'] = numpy.array([int((0+stimDisplayRes[0]/2.0-calibrationDotSize)/2.0),0])
    # calibrationLocations['NE2'] = numpy.array([int((0+stimDisplayRes[0]/2.0-calibrationDotSize)/2.0),int((0-stimDisplayRes[1]/2.0+calibrationDotSize)/2.0)])
    # calibrationLocations['SE2'] = numpy.array([int((0+stimDisplayRes[0]/2.0-calibrationDotSize)/2.0),int((0+stimDisplayRes[1]/2.0-calibrationDotSize)/2.0)])
    # calibrationLocations['NW2'] = numpy.array([int((0-stimDisplayRes[0]/2.0+calibrationDotSize)/2.0),int((0-stimDisplayRes[1]/2.0+calibrationDotSize)/2.0)])
    # calibrationLocations['SW2'] = numpy.array([int((0-stimDisplayRes[0]/2.0+calibrationDotSize)/2.0),int((0+stimDisplayRes[1]/2.0-calibrationDotSize)/2.0)])

    #define a function that will kill everything safely
    def exitSafely():
        qFrom.put(['stopQueing', getTime()])
        sdl2.ext.quit()
        sys.exit()

    #define a function that waits for a given duration to pass
    def simpleWait(duration):
        start = getTime()
        while getTime() < (start + duration):
            sdl2.SDL_PumpEvents()

    #define a function to draw a numpy array on  surface centered on given coordinates
    def blitArray(src, dst, xOffset=0, yOffset=0):
        x1 = dst.shape[0] / 2 + xOffset - src.shape[0] / 2
        y1 = dst.shape[1] / 2 + yOffset - src.shape[1] / 2
        x2 = x1 + src.shape[0]
        y2 = y1 + src.shape[1]
        dst[x1:x2, y1:y2, :] = src

    def blitSurf(srcSurf, dst, dstSurf, xOffset=0, yOffset=0):
        x = dst.size[0] / 2 + xOffset - srcSurf.w / 2
        y = dst.size[1] / 2 + yOffset - srcSurf.h / 2
        sdl2.SDL_BlitSurface(srcSurf, None, dstSurf,
                             sdl2.SDL_Rect(x, y, srcSurf.w, srcSurf.h))
        sdl2.SDL_UpdateWindowSurface(
            dst.window
        )  #should this really be here? (will it cause immediate update?)
        # sdl2.SDL_FreeSurface(srcSurf)

    #define a function that waits for a response
    def waitForResponse():
        # sdl2.SDL_FlushEvents()
        done = False
        while not done:
            sdl2.SDL_PumpEvents()
            for event in sdl2.ext.get_events():
                if event.type == sdl2.SDL_KEYDOWN:
                    response = sdl2.SDL_GetKeyName(
                        event.key.keysym.sym).lower()
                    if response == 'escape':
                        exitSafely()
                    else:
                        done = True
        # sdl2.SDL_FlushEvents()
        return response

    def refreshWindows():
        stimDisplay.refresh()
        image = stimDisplayArray[:, :, 0:3]
        image = scipy.misc.imresize(
            image, (stimDisplayRes[0] / 2, stimDisplayRes[1] / 2),
            interp='nearest')
        mirrorDisplayArray[:, :, 0:3] = image
        mirrorDisplay.refresh()
        return None

    def clearScreen(color):
        sdl2.ext.fill(stimDisplaySurf.contents, color)

    def drawText(myText, myFont, textColor, textWidth=.9):
        lineHeight = sdl2.sdlttf.TTF_RenderText_Blended(
            myFont, 'T', textColor).contents.h
        textWidthMax = int(stimDisplay.size[0])
        paragraphs = myText.splitlines()
        renderList = []
        textHeight = 0
        for thisParagraph in paragraphs:
            words = thisParagraph.split(' ')
            if len(words) == 1:
                renderList.append(words[0])
                if (thisParagraph != paragraphs[len(paragraphs) - 1]):
                    renderList.append(' ')
                    textHeight = textHeight + lineHeight
            else:
                thisWordIndex = 0
                while thisWordIndex < (len(words) - 1):
                    lineStart = thisWordIndex
                    lineWidth = 0
                    while (thisWordIndex <
                           (len(words) - 1)) and (lineWidth <= textWidthMax):
                        thisWordIndex = thisWordIndex + 1
                        lineWidth = sdl2.sdlttf.TTF_RenderText_Blended(
                            myFont,
                            ' '.join(words[lineStart:(thisWordIndex + 1)]),
                            textColor).contents.w
                    if thisWordIndex < (len(words) - 1):
                        #last word went over, paragraph continues
                        renderList.append(' '.join(
                            words[lineStart:(thisWordIndex - 1)]))
                        textHeight = textHeight + lineHeight
                        thisWordIndex = thisWordIndex - 1
                    else:
                        if lineWidth <= textWidthMax:
                            #short final line
                            renderList.append(' '.join(
                                words[lineStart:(thisWordIndex + 1)]))
                            textHeight = textHeight + lineHeight
                        else:
                            #full line then 1 word final line
                            renderList.append(' '.join(
                                words[lineStart:thisWordIndex]))
                            textHeight = textHeight + lineHeight
                            renderList.append(words[thisWordIndex])
                            textHeight = textHeight + lineHeight
                        #at end of paragraph, check whether a inter-paragraph space should be added
                        if (thisParagraph != paragraphs[len(paragraphs) - 1]):
                            renderList.append(' ')
                            textHeight = textHeight + lineHeight
        numLines = len(renderList) * 1.0
        for thisLine in range(len(renderList)):
            thisRender = sdl2.sdlttf.TTF_RenderText_Blended(
                myFont, renderList[thisLine], textColor).contents
            x = int(stimDisplay.size[0] / 2.0 - thisRender.w / 2.0)
            y = int(stimDisplay.size[1] / 2.0 - thisRender.h / 2.0 +
                    1.0 * thisLine / numLines * textHeight)
            sdl2.SDL_BlitSurface(
                thisRender, None, stimDisplaySurf,
                sdl2.SDL_Rect(x, y, thisRender.w, thisRender.h))
            sdl2.SDL_UpdateWindowSurface(
                stimDisplay.window
            )  #should this really be here? (will it cause immediate update?)

    #define a function that prints a message on the stimDisplay while looking for user input to continue. The function returns the total time it waited
    def showMessage(myText, lockWait=False):
        messageViewingTimeStart = getTime()
        clearScreen(black)
        refreshWindows()
        clearScreen(black)
        drawText(myText, font, lightGrey)
        simpleWait(0.500)
        refreshWindows()
        clearScreen(black)
        if lockWait:
            response = None
            while response not in ['return', 'y', 'n']:
                response = waitForResponse()
        else:
            response = waitForResponse()
        refreshWindows()
        clearScreen(black)
        simpleWait(0.500)
        messageViewingTime = getTime() - messageViewingTimeStart
        return [response, messageViewingTime]

    #define a function to show stimuli and collect calibration data
    def getCalibrationData():
        if not manualCalibrationOrder:
            dotLocationList = ['q', 'w', 'e', 'a', 's', 'd', 'z', 'x', 'c']
            random.shuffle(dotLocationList)
        done = False
        eyeData = []
        coordsList = []
        startTimes = []
        stopTimes = []
        qFrom.put('startQueing')
        while not done:
            if manualCalibrationOrder:
                dotLocation = waitForResponse()
            else:
                if len(dotLocationList) == 0:
                    break
                else:
                    dotLocation = dotLocationList.pop()
            if dotLocation == '0':
                phase1Done = True
            elif not dotLocation in calibrationKey:
                pass
            else:
                displayCoords = calibrationLocations[
                    calibrationKey[dotLocation]]
                coordsList.append(displayCoords / PPD)
                clearScreen(black)
                drawDot(displayCoords)
                refreshWindows()
                junk = waitForResponse()
                startTimes.append(getTime())
                simpleWait(1)
                stopTimes.append(getTime())
            while not qTo.empty():
                eyeData.append(qTo.get())
        clearScreen(black)
        refreshWindows()
        qFrom.put(['stopQueing', getTime()])
        simpleWait(1)
        done = False
        while not done:
            if not qTo.empty():
                message = qTo.get()
                if message == 'doneQueing':
                    done = True
                else:
                    eyeData.append(message)
        calibrationData = []
        for i in range(len(startTimes)):
            temp = [[
                list(coordsList[i])[0],
                list(coordsList[i])[1], 1.0, e[1], e[2], e[1] * e[2], e[3],
                e[4], e[3] * e[4]
            ] for e in eyeData
                    if ((e[0] > startTimes[i]) and (e[0] < stopTimes[i]))]
            temp = [item for sublist in temp for item in sublist]
            calibrationData.append(temp)

        calibrationData = numpy.array(
            [item for sublist in calibrationData for item in sublist])
        calibrationData = calibrationData.reshape(
            [len(calibrationData) / 9, 9])
        return calibrationData

    #define a function to compute prediciton error
    def getErrors(calibrationData, xCoefLeft, xCoefRight, yCoefLeft,
                  yCoefRight, leftCols, rightCols):
        xPredsLeft = xCoefLeft[0] + xCoefLeft[1] * calibrationData[:, leftCols[
            1]] + xCoefLeft[2] * calibrationData[:, leftCols[2]] + xCoefLeft[
                3] * calibrationData[:, leftCols[3]]
        yPredsLeft = yCoefLeft[0] + yCoefLeft[1] * calibrationData[:, leftCols[
            1]] + yCoefLeft[2] * calibrationData[:, leftCols[2]] + yCoefLeft[
                3] * calibrationData[:, leftCols[3]]
        xPredsRight = xCoefRight[
            0] + xCoefRight[1] * calibrationData[:, rightCols[1]] + xCoefRight[
                2] * calibrationData[:, rightCols[2]] + xCoefRight[
                    3] * calibrationData[:, rightCols[3]]
        yPredsRight = yCoefRight[
            0] + yCoefRight[1] * calibrationData[:, rightCols[1]] + yCoefRight[
                2] * calibrationData[:, rightCols[2]] + yCoefRight[
                    3] * calibrationData[:, rightCols[3]]
        xPreds = (xPredsLeft + xPredsRight) / 2
        yPreds = (yPredsLeft + yPredsRight) / 2
        xError = numpy.mean((xPreds - calibrationData[:, 0])**2)**.5
        yError = numpy.mean((yPreds - calibrationData[:, 1])**2)**.5
        totError = numpy.mean((((xPreds - calibrationData[:, 0])**2) +
                               (yPreds - calibrationData[:, 1])**2)**.5)
        return [xError, yError, totError]

    #start calibration
    done = False
    while not done:
        showMessage('When you are ready to begin calibration, press any key.')
        calibrationData = getCalibrationData()
        leftCols = [2, 3, 4, 5]
        rightCols = [2, 6, 7, 8]
        xCoefLeft = numpy.linalg.lstsq(calibrationData[:, leftCols],
                                       calibrationData[:, 0])[0]
        xCoefRight = numpy.linalg.lstsq(calibrationData[:, rightCols],
                                        calibrationData[:, 0])[0]
        yCoefLeft = numpy.linalg.lstsq(calibrationData[:, leftCols],
                                       calibrationData[:, 1])[0]
        yCoefRight = numpy.linalg.lstsq(calibrationData[:, rightCols],
                                        calibrationData[:, 1])[0]
        xError, yError, totError = getErrors(calibrationData, xCoefLeft,
                                             xCoefRight, yCoefLeft, yCoefRight,
                                             leftCols, rightCols)
        showMessage('Calibration results:\nx = ' + str(xError) + '\ny = ' +
                    str(yError) + '\nz = ' + str(totError) +
                    '\nPress any key to validate calibration.')
        validationData = getCalibrationData()
        xError, yError, totError = getErrors(validationData, xCoefLeft,
                                             xCoefRight, yCoefLeft, yCoefRight,
                                             leftCols, rightCols)
        done2 = False
        while not done2:
            response = showMessage(
                'Validation results:\nx = ' + str(xError) + '\ny = ' +
                str(yError) + '\nz = ' + str(totError) +
                '\nExperimenter: Press "a" to accept calibration, or "r" to repeat calibration.'
            )
            if response[0] == 'a':
                qFrom.put([
                    'calibrationCoefs',
                    [xCoefLeft, xCoefRight, yCoefLeft, yCoefRight]
                ])
                done = True
                done2 = True
            elif response[0] == 'r':
                done2 = True
    exitSafely()
示例#15
0
import math
 
# Connect to the controller (joystick) using SDL
sdl2.SDL_Init(sdl2.SDL_INIT_JOYSTICK)
joystick = sdl2.SDL_JoystickOpen(0)
 
# Open the NXT Bluetooth connection
conn = Connection('/dev/tty.NXT-DevB')

# Helper function to limit the range of a value 
def clamp(n, minn, maxn):
    return max(min(maxn, n), minn)
 
# Main loop
while True:
    sdl2.SDL_PumpEvents()
 
    # Read controller stick Y-inputs and normalize the value
    # to a range of -100 to 100
    joy_1 = -sdl2.SDL_JoystickGetAxis(joystick, 1) / 327.67
    joy_3 = -sdl2.SDL_JoystickGetAxis(joystick, 3) / 327.67

    m1 = clamp(joy_1,-100,100)
    m2 = clamp(joy_3,-100,100)

    # Check left/right triggers (10,11) for 3rd motor control
    if sdl2.SDL_JoystickGetButton(joystick, 10): m0 = -30
    elif sdl2.SDL_JoystickGetButton(joystick, 11): m0 = 30
    else: m0 = 0
 
    # Print values to console (mostly for debugging)
示例#16
0
文件: core.py 项目: a-hurst/klibs
def display_init(diagonal_in):
    """Initializes the display and rendering backend, calculating and assigning the values
		of runtime KLParams variables related to the screen (e.g. P.screen_c, P.refresh_rate,
		P.pixels_per_degree). Called by 'klibs run' on launch, for internal use only.
		
		Args:
			diagonal_in (float): The size of the monitor in diagonal inches (e.g. 13 for a
				13-inch MacBook Pro).

		"""
    if os.name == 'nt':
        # set video driver explicitly on Windows to avoid misdetection problems
        os.environ['SDL_VIDEODRIVER'] = 'windows'

    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    sdl2.mouse.SDL_ShowCursor(sdl2.SDL_DISABLE)
    sdl2.SDL_PumpEvents()

    display_mode = sdl2.video.SDL_DisplayMode()
    sdl2.SDL_GetCurrentDisplayMode(0, display_mode)

    P.screen_x = display_mode.w
    P.screen_y = display_mode.h
    P.screen_c = (P.screen_x // 2, P.screen_y // 2)
    P.screen_x_y = (P.screen_x, P.screen_y)

    P.refresh_rate = float(display_mode.refresh_rate)
    if P.refresh_rate == 0:
        P.refresh_rate = 60.0
        print(
            "\tWarning: Unable to detect your monitor's refresh rate, defaulting to 60Hz."
        )
    elif P.refresh_rate == 59:
        P.refresh_rate = 59.94  # fix for some Windows monitors
    P.refresh_time = 1000.0 / P.refresh_rate

    #TODO: figure out what's actually needed for multi-monitor support
    for d in P.additional_displays:
        if d[2]:
            P.screen_x_y = list(d[1])
            P.screen_x = d[1][0]
            P.screen_y = d[1][1]

    if P.screen_origin is None:
        P.screen_origin = (0, 0)

    # Get conversion factor for pixels to degrees of visual angle based on viewing distance,
    # screen resolution, and given diagonal screen size
    P.screen_diagonal_in = diagonal_in
    P.screen_diagonal_px = sqrt(P.screen_x**2.0 + P.screen_y**2.0)
    P.ppi = P.screen_diagonal_px / diagonal_in
    P.monitor_height = P.screen_y / P.ppi
    P.monitor_width = P.screen_x / P.ppi
    P.screen_degrees_x = degrees(2 * atan(
        (2.54 * P.monitor_width / 2.0) / P.view_distance))
    P.screen_degrees_y = degrees(2 * atan(
        (2.54 * P.monitor_height / 2.0) / P.view_distance))
    P.pixels_per_degree = P.screen_x / P.screen_degrees_x
    P.ppd = P.pixels_per_degree  # alias for convenience

    # Create the SDL window object and configure it properly for OpenGL (code from Mike)
    SCREEN_FLAGS = (sdl2.SDL_WINDOW_SHOWN | sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP
                    | sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_ALLOW_HIGHDPI)
    window = sdl2.ext.Window(P.project_name, P.screen_x_y, P.screen_origin,
                             SCREEN_FLAGS)
    sdl2.SDL_GL_CreateContext(window.window)
    sdl2.SDL_GL_SetSwapInterval(1)  # enforce vsync
    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.glLoadIdentity()
    gl.glOrtho(0, P.screen_x, P.screen_y, 0, 0, 1)
    gl.glMatrixMode(gl.GL_MODELVIEW)
    gl.glDisable(gl.GL_DEPTH_TEST)

    # Clear the SDL event queue and open the window, returning the window object
    sdl2.SDL_PumpEvents()
    sdl2.mouse.SDL_ShowCursor(sdl2.SDL_DISABLE)
    window.show()
    P.display_initialized = True
    return window
示例#17
0
 def simpleWait(duration):
     start = getTime()
     while getTime() < (start + duration):
         sdl2.SDL_PumpEvents()
示例#18
0
def trackerChildFunction(qTo,
                         qFrom,
                         camIndex=0,
                         camRes=[1920, 1080],
                         previewDownsize=2,
                         previewLoc=[0, 0],
                         faceDetectionScale=10,
                         eyeDetectionScale=5,
                         timestampMethod=0,
                         viewingDistance=100,
                         stimDisplayWidth=100,
                         stimDisplayRes=[1920, 1080],
                         stimDisplayPosition=[0, 0],
                         mirrorDisplayPosition=[0, 0],
                         mirrorDownSize=2,
                         manualCalibrationOrder=True,
                         calibrationDotSizeInDegrees=.5):
    import fileForker
    import numpy
    import cv2
    import scipy.ndimage.filters
    # import scipy.interpolate
    import sys
    import sdl2
    import sdl2.ext
    import sdl2.sdlmixer

    #define a class for a clickable text UI
    class clickableText:
        def __init__(self, x, y, text, rightJustified=False, valueText=''):
            self.x = x
            self.y = y
            self.text = text
            self.rightJustified = rightJustified
            self.valueText = valueText
            self.isActive = False
            self.clicked = False
            self.updateSurf()

        def updateSurf(self):
            if self.isActive:
                self.surf = sdl2.sdlttf.TTF_RenderText_Blended_Wrapped(
                    font, self.text + self.valueText,
                    sdl2.pixels.SDL_Color(r=0, g=255, b=255, a=255),
                    previewWindow.size[0]).contents
            else:
                self.surf = sdl2.sdlttf.TTF_RenderText_Blended_Wrapped(
                    font, self.text + self.valueText,
                    sdl2.pixels.SDL_Color(r=0, g=0, b=255, a=255),
                    previewWindow.size[0]).contents

        def checkIfActive(self, event):
            if self.rightJustified:
                xLeft = self.x - self.surf.w
                xRight = self.x
            else:
                xLeft = self.x
                xRight = self.x + self.surf.w
            if (event.button.x > xLeft) & (event.button.x < xRight) & (
                    event.button.y > self.y) & (event.button.y <
                                                (self.y + fontSize)):
                self.isActive = True
            else:
                self.isActive = False
            self.updateSurf()

        def draw(self, targetWindowSurf):
            if self.rightJustified:
                sdl2.SDL_BlitSurface(
                    self.surf, None, targetWindowSurf,
                    sdl2.SDL_Rect(self.x - self.surf.w, self.y, self.surf.w,
                                  self.surf.h))
            else:
                sdl2.SDL_BlitSurface(
                    self.surf, None, targetWindowSurf,
                    sdl2.SDL_Rect(self.x, self.y, self.surf.w, self.surf.h))

    #define a class for settings
    class settingText(clickableText):
        def __init__(self, value, x, y, text, rightJustified=False):
            self.value = value
            self.valueText = str(value)
            clickableText.__init__(self, x, y, text, rightJustified,
                                   self.valueText)

        def addValue(self, toAdd):
            self.valueText = self.valueText + toAdd
            self.updateSurf()

        def delValue(self):
            if self.valueText != '':
                self.valueText = self.valueText[0:(len(self.valueText) - 1)]
                self.updateSurf()

        def finalizeValue(self):
            try:
                self.value = int(self.valueText)
            except:
                print 'Non-numeric value entered!'

    #define a class for dots
    class dotObj:
        def __init__(self, name, isFid, fid, xPixel, yPixel, radiusPixel,
                     blinkCriterion, blurSize, filterSize):
            self.name = name
            self.isFid = isFid
            self.x = xPixel
            self.y = yPixel
            self.radius = radiusPixel
            self.first = True
            self.last = [self.x, self.y, self.radius]
            self.lost = False
            self.blinkHappened = False
            self.radii = []
            self.SDs = []
            self.lostCount = 0
            self.blinkCriterion = blinkCriterion
            self.blurSize = blurSize
            self.filterSize = filterSize
            self.setPixels()
            if not self.isFid:
                self.makeRelativeToFid(fid)

        def setPixels(self):
            self.xPixel = int(self.x)
            self.yPixel = int(self.y)
            self.radiusPixel = int(self.radius)
            return None

        def makeRelativeToFid(self, fid):
            self.x2 = (self.x - fid.x) / fid.radius
            self.y2 = (self.y - fid.y) / fid.radius
            self.radius2 = self.radius / fid.radius
            return None

        def getDarkEllipse(self, img):
            #if not self.isFid:
            #	#cv2.imwrite(self.name + "_" + "%.2d" % imageNum + "_raw.png" , img)
            try:
                smoothedImg = cv2.GaussianBlur(img,
                                               (self.blurSize, self.blurSize),
                                               0)
                #if not self.isFid:
                #	#cv2.imwrite(self.name + "_" + "%.2d" % imageNum + "_smoothed.png" , img)
            except:
                print 'cv2.GaussianBlur failed'
                # cv2.imwrite('temp.png',img)
                return None
            try:
                dataMin = scipy.ndimage.filters.minimum_filter(
                    smoothedImg, self.filterSize)
            except:
                print 'scipy.ndimage.filters.minimum_filter failed'
                # cv2.imwrite('temp.png',img)
                return None
            if dataMin != None:
                try:
                    minLocs = numpy.where(
                        dataMin < (numpy.min(dataMin) + numpy.std(dataMin)))
                except:
                    print 'numpy.where failed'
                    # cv2.imwrite('temp.png',img)
                    return None
                if len(minLocs[0]) >= 5:
                    try:
                        ellipse = cv2.fitEllipse(
                            numpy.reshape(
                                numpy.column_stack((minLocs[1], minLocs[0])),
                                (len(minLocs[0]), 1, 2)))
                    except:
                        print 'cv2.fitEllipse failed'
                        # cv2.imwrite('temp.png',img)
                        return None
                    return ellipse

        def cropImage(self, img, cropSize):
            xLo = self.xPixel - cropSize
            if xLo < 0:
                xLo = 0
            xHi = self.xPixel + cropSize
            if xHi > img.shape[1]:
                xHi = img.shape[1]
            yLo = self.yPixel - cropSize
            if yLo < 0:
                yLo = 0
            yHi = self.yPixel + cropSize
            if yHi > img.shape[0]:
                yHi = img.shape[0]
            return [img[yLo:yHi, xLo:xHi], xLo, xHi, yLo, yHi]

        def search(self, img):
            if self.first and self.isFid:
                searchSize = 1
            elif self.lost:
                searchSize = 5
            else:
                searchSize = 3
            if self.first:
                self.first = False
            img, xLo, xHi, yLo, yHi = self.cropImage(img=img,
                                                     cropSize=searchSize *
                                                     self.radiusPixel)
            self.ellipse = self.getDarkEllipse(img=img)
            if self.ellipse != None:
                self.ellipse = ((self.ellipse[0][0] + xLo,
                                 self.ellipse[0][1] + yLo), self.ellipse[1],
                                self.ellipse[2])
                self.lost = False
                self.x = self.ellipse[0][0]
                self.y = self.ellipse[0][1]
                self.major = self.ellipse[1][0]
                self.minor = self.ellipse[1][1]
                self.angle = self.ellipse[2]
                self.radius = (self.ellipse[1][0] + self.ellipse[1][1]) / 4
                self.setPixels()
            else:
                self.lost = True

        def checkSearch(self):
            self.medianRadius = numpy.median(self.radii)
            self.critRadius = 10 * ((numpy.median(
                (self.radii - self.medianRadius)**2))**.5)
            #print [self.name, self.radius2,(self.radius2<(1/6)) , (self.radius2>2)]
            if len(self.radii) < 30:
                self.radii.append(self.radius2)
                self.lost = False
            else:
                #fid diameter is 6mm, so range from 1mm to 12mm
                #if (self.radius2<(1/6)) or (self.radius2>2) or (self.radius2<(self.medianRadius - self.critRadius)) or (self.radius2>(self.medianRadius + self.critRadius)):
                if (self.radius2 < (1 / 6)) or (self.radius2 > 2):
                    self.lost = True
                else:
                    self.lost = False
                    self.radii.append(self.radius2)
                if len(self.radii) >= 300:
                    self.radii.pop()

        def checkSD(self, img, fid):
            self.obsSD = numpy.std(
                self.cropImage(img=img, cropSize=5 * fid.radiusPixel)[0])
            self.medianSD = numpy.median(self.SDs)
            self.critSD = self.medianSD * self.blinkCriterion
            #print [self.name,self.obsSD,self.medianSD,self.critSD,self.blinkCriterion]
            if len(self.SDs) < 30:
                self.SDs.append(self.obsSD)
                self.blinkHappened = False
            else:
                if (self.obsSD < self.critSD):
                    self.blinkHappened = True
                else:
                    self.SDs.append(self.obsSD)
                    self.blinkHappened = False
                if len(self.SDs) >= 300:
                    self.SDs.pop()

        def update(self, img, fid, blinkCriterion, blurSize, filterSize):
            self.blinkCriterion = blinkCriterion
            self.blurSize = blurSize
            self.filterSize = filterSize
            self.last = [self.x, self.y, self.radius]
            if self.isFid:
                self.search(img=img)
            else:
                self.checkSD(
                    img=img, fid=fid
                )  #alters the value of self.blinkHappened, amongst other things
                if self.blinkHappened:
                    self.x, self.y, self.radius = self.last
                    self.setPixels()
                    self.makeRelativeToFid(fid)
                else:
                    self.search(
                        img=img
                    )  #alters the value of self.lost, amongst other things
                    if self.lost:
                        self.x, self.y, self.radius = self.last
                        self.setPixels()
                        self.makeRelativeToFid(fid)
                    else:
                        self.makeRelativeToFid(fid=fid)
                        self.checkSearch(
                        )  #alters the value of self.lost, among other things
                        if self.lost:
                            self.x, self.y, self.radius = self.last
                            self.setPixels()
                            self.makeRelativeToFid(fid)
            if self.lost and not self.blinkHappened:
                self.lostCount += 1
            else:
                self.lostCount = 0

    ########
    # Initialize audio and define a class that handles playing sounds in PySDL2
    ########
    sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
    sdl2.sdlmixer.Mix_OpenAudio(44100, sdl2.sdlmixer.MIX_DEFAULT_FORMAT, 2,
                                1024)

    class Sound:
        def __init__(self, fileName):
            self.sample = sdl2.sdlmixer.Mix_LoadWAV(
                sdl2.ext.compat.byteify(fileName, "utf-8"))
            self.started = False

        def play(self):
            self.channel = sdl2.sdlmixer.Mix_PlayChannel(-1, self.sample, 0)
            self.started = True

        def stillPlaying(self):
            if self.started:
                if sdl2.sdlmixer.Mix_Playing(self.channel):
                    return True
                else:
                    self.started = False
                    return False

    ########
    # define some useful functions
    ########

    #define a function to exit safely
    def exitSafely():
        qFrom.put('done')
        sys.exit()

    #define a function to rescale
    def rescaleBiggestHaar(detected, scale, addToX=0, addToY=0):
        x, y, w, h = detected[numpy.argmax(
            [numpy.sqrt(w * w + h * h) for x, y, w, h in detected])]
        return [x * scale + addToX, y * scale + addToY, w * scale, h * scale]

    ########
    # Initialize variables
    ########

    #initialize sounds
    blinkSound = Sound('./pytracker/Resources/sounds/beep.wav')
    saccadeSound = Sound('./pytracker/Resources/sounds/stop.wav')

    #specify the getTime function
    if (timestampMethod == 0) or (timestampMethod == 1):
        #initialize timer
        sdl2.SDL_Init(sdl2.SDL_INIT_TIMER)
        if timestampMethod == 0:
            #define a function to use the high-precision timer, returning a float in seconds
            def getTime():
                return sdl2.SDL_GetPerformanceCounter(
                ) * 1.0 / sdl2.SDL_GetPerformanceFrequency()
        elif timestampMethod == 1:
            #use the SDL_GetTicks timer
            def getTime():
                return sdl2.SDL_GetTicks() / 1000.0
    elif timestampMethod == 2:
        #use time.time
        import time
        getTime = time.time

    #initialize font
    fontSize = camRes[1] / previewDownsize / 10
    sdl2.sdlttf.TTF_Init()
    font = sdl2.sdlttf.TTF_OpenFont('./pytracker/Resources/DejaVuSans.ttf',
                                    fontSize)

    #initialize preview video
    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    previewWindow = sdl2.ext.Window("Preview",
                                    size=(camRes[0] / previewDownsize,
                                          camRes[1] / previewDownsize),
                                    position=previewLoc,
                                    flags=sdl2.SDL_WINDOW_SHOWN)
    previewWindowSurf = sdl2.SDL_GetWindowSurface(previewWindow.window)
    previewWindowArray = sdl2.ext.pixels3d(previewWindowSurf.contents)
    sdl2.ext.fill(previewWindowSurf.contents,
                  sdl2.pixels.SDL_Color(r=255, g=255, b=255, a=255))
    previewWindow.refresh()
    lastRefreshTime = getTime()

    #initialize the settings window
    settingsWindow = sdl2.ext.Window(
        "Settings",
        size=(camRes[0] / previewDownsize, camRes[1] / previewDownsize),
        position=[
            previewLoc[0] + camRes[0] / previewDownsize + 1, previewLoc[1]
        ])
    settingsWindowSurf = sdl2.SDL_GetWindowSurface(settingsWindow.window)
    settingsWindowArray = sdl2.ext.pixels3d(settingsWindowSurf.contents)
    sdl2.ext.fill(settingsWindowSurf.contents,
                  sdl2.pixels.SDL_Color(r=0, g=0, b=0, a=255))
    settingsWindow.hide()
    settingsWindow.refresh()

    #import the haar cascades
    faceCascade = cv2.CascadeClassifier(
        './pytracker/Resources/cascades/haarcascade_frontalface_alt2.xml')
    eyeLeftCascade = cv2.CascadeClassifier(
        './pytracker/Resources/cascades/LEye18x12.1.xml')
    eyeRightCascade = cv2.CascadeClassifier(
        './pytracker/Resources/cascades/REye18x12.1.xml')

    #create some settings
    settingsDict = {}
    settingsDict['blink'] = settingText(value=75,
                                        x=fontSize,
                                        y=fontSize,
                                        text='Blink (0-100) = ')
    settingsDict['blur'] = settingText(value=3,
                                       x=fontSize,
                                       y=fontSize * 2,
                                       text='Blur (0-; odd only) = ')
    settingsDict['filter'] = settingText(value=3,
                                         x=fontSize,
                                         y=fontSize * 3,
                                         text='Filter (0-; odd only) = ')
    settingsDict['saccade0'] = settingText(value=50,
                                           x=fontSize,
                                           y=fontSize * 4,
                                           text='Saccade (0-) = ')
    settingsDict['saccade'] = settingText(value=1,
                                          x=fontSize,
                                          y=fontSize * 5,
                                          text='Calibrated Saccade (0-) = ')

    #create some text UIs
    clickableTextDict = {}
    clickableTextDict['manual'] = clickableText(x=0, y=0, text='Manual')
    clickableTextDict['auto'] = clickableText(x=0, y=fontSize, text='Auto')
    clickableTextDict['calibrate'] = clickableText(x=0,
                                                   y=previewWindow.size[1] -
                                                   fontSize,
                                                   text='Calibrate')
    clickableTextDict['settings'] = clickableText(x=previewWindow.size[0],
                                                  y=0,
                                                  text='Settings',
                                                  rightJustified=True)
    clickableTextDict['lag'] = clickableText(x=previewWindow.size[0],
                                             y=previewWindow.size[1] -
                                             fontSize * 2,
                                             text='Lag: ',
                                             rightJustified=True)
    clickableTextDict['f2f'] = clickableText(x=previewWindow.size[0],
                                             y=previewWindow.size[1] -
                                             fontSize,
                                             text='Frame-to-frame: ',
                                             rightJustified=True)

    #initialize variables
    previewInFocus = True
    settingsInFocus = False
    lastTime = 0
    dotList = []
    lastLocs = [None, None]
    displayLagList = []
    frameToFrameTimeList = []
    doHaar = False
    clickingForDots = False
    calibrating = False
    doneCalibration = False
    doSounds = True
    queueDataToParent = False

    #set dummy calibration coefficients (yields untransformed pixel locs)
    calibrationCoefs = [[0, 1, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 0]]

    ########
    # Initialize camera
    ########
    vc = cv2.VideoCapture(camIndex)
    vc.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, camRes[0])
    vc.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, camRes[1])
    imageNum = 0

    #start the loop
    while True:

        #poll the camera
        t1 = getTime()  #time right before requesting the image
        _, image = vc.read()  #request the image
        t2 = getTime()  #time right after requesting the image
        imageTime = t1 + (
            t2 - t1
        ) / 2.0  #timestamp the image as halfway between times before and after request
        image = image[:, :, 2]  #grab red channel (image is BGR)
        imageNum += 1  #iterate the image number

        #check for messages from the main process
        if not qTo.empty():
            message = qTo.get()
            if message == 'quit':
                exitSafely()

        #process input
        sdl2.SDL_PumpEvents()
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_WINDOWEVENT:
                targetWindow = sdl2.SDL_GetWindowFromID(event.window.windowID)
                title = sdl2.SDL_GetWindowTitle(targetWindow)
                # if event.window.event==sdl2.SDL_WINDOWEVENT_FOCUS_GAINED:
                # 	print title + "focused"
                # if event.window.event==sdl2.SDL_WINDOWEVENT_ENTER:
                # 	print title + " entered"
                # elif event.window.event==sdl2.SDL_WINDOWEVENT_FOCUS_LOST:
                # 	print title + " lost focus"
                if event.window.event == sdl2.SDL_WINDOWEVENT_LEAVE:
                    if title == 'Preview':
                        previewInFocus = False
                        settingsInFocus = True
                if (event.window.event == sdl2.SDL_WINDOWEVENT_FOCUS_GAINED
                    ) or (event.window.event == sdl2.SDL_WINDOWEVENT_ENTER):
                    if title == 'Preview':
                        previewInFocus = True
                        settingsInFocus = False
                    elif title == 'Settings':
                        previewInFocus = False
                        settingsInFocus = True
                elif (event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE):
                    if title == 'Preview':
                        exitSafely()
                    elif title == 'Settings':
                        previewInFocus = True
                        settingsInFocus = False
                        settingsWindow.hide()
                        previewWindow.show()
            elif settingsInFocus:
                # if event.type==sdl2.SDL_MOUSEBUTTONUP:
                # 	if blinkTextButtonDown:
                # 		blinkTextButtonDown = False
                # if event.type==sdl2.SDL_MOUSEBUTTONDOWN:
                # 	if mouseInBlinkText:
                # 		blinkTextButtonDown = True
                if event.type == sdl2.SDL_MOUSEMOTION:
                    alreadyClicked = False
                    for setting in settingsDict:
                        if (settingsDict[setting].isActive) and (
                                settingsDict[setting].clicked):
                            alreadyClicked = True
                    if not alreadyClicked:
                        for setting in settingsDict:
                            settingsDict[setting].checkIfActive(event)
                elif event.type == sdl2.SDL_MOUSEBUTTONDOWN:
                    alreadyClicked = False
                    for setting in settingsDict:
                        if (settingsDict[setting].isActive) and (
                                settingsDict[setting].clicked):
                            alreadyClicked = True
                    if not alreadyClicked:
                        for setting in settingsDict:
                            if settingsDict[setting].isActive:
                                settingsDict[setting].clicked = True
                elif event.type == sdl2.SDL_KEYDOWN:
                    key = sdl2.SDL_GetKeyName(event.key.keysym.sym).lower()
                    if key == 'backspace':
                        for setting in settingsDict:
                            if (settingsDict[setting].isActive) and (
                                    settingsDict[setting].clicked):
                                settingsDict[setting].delValue()
                    elif key == 'return':
                        for setting in settingsDict:
                            if (settingsDict[setting].isActive) and (
                                    settingsDict[setting].clicked):
                                settingsDict[setting].finalizeValue()
                                settingsDict[setting].clicked = False
                    else:
                        for setting in settingsDict:
                            if (settingsDict[setting].isActive) and (
                                    settingsDict[setting].clicked):
                                settingsDict[setting].addValue(key)
            elif previewInFocus:
                if event.type == sdl2.SDL_KEYDOWN:
                    key = sdl2.SDL_GetKeyName(event.key.keysym.sym).lower()
                    if key == 'escape':  #exit
                        # exitSafely()
                        clickingForDots = False
                        clickingForFid = False
                        definingFidFinderBox = False
                        dotList = []
                if event.type == sdl2.SDL_MOUSEMOTION:
                    if clickingForDots:
                        clickableTextDict[
                            'manual'].isActive = True  #just making sure
                        if definingFidFinderBox:
                            fidFinderBoxSize = abs(fidFinderBoxX -
                                                   (previewWindow.size[0] -
                                                    event.button.x))
                    else:
                        for clickableText in clickableTextDict:
                            if not (clickableText in ['lag', 'f2f']):
                                clickableTextDict[clickableText].checkIfActive(
                                    event)
                if event.type == sdl2.SDL_MOUSEBUTTONDOWN:
                    if clickingForDots:
                        if clickingForFid:
                            if not definingFidFinderBox:
                                definingFidFinderBox = True
                                fidFinderBoxX = previewWindow.size[
                                    0] - event.button.x
                                fidFinderBoxY = event.button.y
                                fidFinderBoxSize = 0
                            else:
                                definingFidFinderBox = False
                                clickingForFid = False
                                fidFinderBoxSize = abs(fidFinderBoxX -
                                                       (previewWindow.size[0] -
                                                        event.button.x))
                                dotList.append(
                                    dotObj(
                                        name='fid',
                                        isFid=True,
                                        fid=None,
                                        xPixel=fidFinderBoxX * previewDownsize,
                                        yPixel=fidFinderBoxY * previewDownsize,
                                        radiusPixel=fidFinderBoxSize *
                                        previewDownsize,
                                        blinkCriterion=settingsDict['blink'].
                                        value / 100.0,
                                        blurSize=settingsDict['blur'].value,
                                        filterSize=settingsDict['filter'].value
                                    ))
                        else:
                            clickX = (previewWindow.size[0] - event.button.x)
                            clickY = event.button.y
                            if len(dotList) == 1:
                                dotList.append(
                                    dotObj(
                                        name='left',
                                        isFid=False,
                                        fid=dotList[0],
                                        xPixel=clickX * previewDownsize,
                                        yPixel=clickY * previewDownsize,
                                        radiusPixel=dotList[0].radiusPixel,
                                        blinkCriterion=settingsDict['blink'].
                                        value / 100.0,
                                        blurSize=settingsDict['blur'].value,
                                        filterSize=settingsDict['filter'].value
                                    ))
                            else:
                                dotList.append(
                                    dotObj(
                                        name='right',
                                        isFid=False,
                                        fid=dotList[0],
                                        xPixel=clickX * previewDownsize,
                                        yPixel=clickY * previewDownsize,
                                        radiusPixel=dotList[1].radiusPixel,
                                        blinkCriterion=settingsDict['blink'].
                                        value / 100.0,
                                        blurSize=settingsDict['blur'].value,
                                        filterSize=settingsDict['filter'].value
                                    ))
                                clickingForDots = False
                                manTextSurf = sdl2.sdlttf.TTF_RenderText_Blended_Wrapped(
                                    font, 'Manual',
                                    sdl2.pixels.SDL_Color(r=0,
                                                          g=0,
                                                          b=255,
                                                          a=255),
                                    previewWindow.size[0]).contents
                    else:
                        if clickableTextDict['settings'].isActive:
                            if (sdl2.SDL_GetWindowFlags(settingsWindow.window)
                                    & sdl2.SDL_WINDOW_SHOWN):
                                settingsWindow.hide()
                            else:
                                settingsWindow.show()
                        elif clickableTextDict['auto'].isActive:
                            waitingforHaar = False
                            doHaar = True  #triggers haar detection for next frame
                            dotList = []
                        elif clickableTextDict['manual'].isActive:
                            clickingForDots = True
                            clickingForFid = True
                            definingFidFinderBox = False
                            dotList = []
                        elif clickableTextDict['calibrate'].isActive:
                            doneCalibration = False
                            calibrationChild = fileForker.childClass(
                                childFile='calibrationChild')
                            calibrationChild.initDict[
                                'timestampMethod'] = timestampMethod
                            calibrationChild.initDict[
                                'viewingDistance'] = viewingDistance
                            calibrationChild.initDict[
                                'stimDisplayWidth'] = stimDisplayWidth
                            calibrationChild.initDict[
                                'stimDisplayRes'] = stimDisplayRes
                            calibrationChild.initDict[
                                'stimDisplayPosition'] = stimDisplayPosition
                            calibrationChild.initDict[
                                'mirrorDisplayPosition'] = mirrorDisplayPosition
                            calibrationChild.initDict[
                                'mirrorDownSize'] = mirrorDownSize
                            calibrationChild.initDict[
                                'calibrationDotSizeInDegrees'] = calibrationDotSizeInDegrees
                            calibrationChild.initDict[
                                'manualCalibrationOrder'] = manualCalibrationOrder
                            calibrationChild.start()
                            calibrating = True
                            checkCalibrationStopTime = False
                            queueDataToCalibrationChild = False

        #do haar detection if requested
        if doHaar:
            doHaar = False  #only enter this section once
            faceDetectionImage = cv2.resize(
                image,
                dsize=(image.shape[1] / faceDetectionScale,
                       image.shape[0] / faceDetectionScale),
                interpolation=cv2.INTER_NEAREST)
            detectedFaces = faceCascade.detectMultiScale(
                faceDetectionImage
            )  #,scaleFactor=1.1,minNeighbors=3,minSize=(10,10))
            if len(detectedFaces) == 0:  #no faces found!
                print 'no faces found!'  #do something here
            else:
                faceX, faceY, faceW, faceH = rescaleBiggestHaar(
                    detected=detectedFaces,
                    scale=faceDetectionScale,
                    addToX=0,
                    addToY=0)
                leftFaceImage = image[faceY:(faceY + faceH),
                                      faceX:(faceX + faceW / 2)]
                eyeLeftDetectionImage = cv2.resize(
                    leftFaceImage,
                    dsize=(leftFaceImage.shape[1] / eyeDetectionScale,
                           leftFaceImage.shape[0] / eyeDetectionScale),
                    interpolation=cv2.INTER_NEAREST)
                detectedEyeLefts = eyeLeftCascade.detectMultiScale(
                    eyeLeftDetectionImage
                )  #,minSize=(leftFaceImage.shape[0]/8,leftFaceImage.shape[0]/8))
                rightFaceImage = image[faceY:(faceY + faceH),
                                       (faceX + faceW / 2):(faceX + faceW)]
                eyeRightDetectionImage = cv2.resize(
                    rightFaceImage,
                    dsize=(rightFaceImage.shape[1] / eyeDetectionScale,
                           rightFaceImage.shape[0] / eyeDetectionScale),
                    interpolation=cv2.INTER_NEAREST)
                detectedEyeRights = eyeRightCascade.detectMultiScale(
                    eyeRightDetectionImage
                )  #,minSize=(rightFaceImage.shape[0]/8,rightFaceImage.shape[0]/8))
                if (len(detectedEyeLefts)
                        == 0) | (len(detectedEyeRights)
                                 == 0):  #at least one eye is missing!
                    if (len(detectedEyeLefts) == 0):
                        print 'left eye missing'  #do something here
                    else:
                        print 'right eye missing'  #do something here
                else:
                    eyeLeftX, eyeLeftY, eyeLeftW, eyeLeftH = rescaleBiggestHaar(
                        detected=detectedEyeLefts,
                        scale=eyeDetectionScale,
                        addToX=faceX,
                        addToY=faceY)
                    eyeRightX, eyeRightY, eyeRightW, eyeRightH = rescaleBiggestHaar(
                        detected=detectedEyeRights,
                        scale=eyeDetectionScale,
                        addToX=faceX + faceW / 2,
                        addToY=faceY)
                    #initialize fid
                    dotList.append(
                        dotObj(name='fid',
                               isFid=True,
                               fid=None,
                               xPixel=faceX + faceW / 2,
                               yPixel=(faceY + (eyeLeftY + eyeRightY) / 2) / 2,
                               radiusPixel=(eyeLeftH + eyeRightH) / 4,
                               blinkCriterion=settingsDict['blink'].value /
                               100.0,
                               blurSize=settingsDict['blur'].value,
                               filterSize=settingsDict['filter'].value))
                    #initialize left
                    dotList.append(
                        dotObj(name='left',
                               isFid=False,
                               fid=dotList[0],
                               xPixel=eyeLeftX + eyeLeftW / 2,
                               yPixel=eyeLeftY + eyeLeftH / 2,
                               radiusPixel=eyeLeftH / 2,
                               blinkCriterion=settingsDict['blink'].value /
                               100.0,
                               blurSize=settingsDict['blur'].value,
                               filterSize=settingsDict['filter'].value))
                    #initialize right
                    dotList.append(
                        dotObj(name='right',
                               isFid=False,
                               fid=dotList[0],
                               xPixel=eyeRightX + eyeRightW / 2,
                               yPixel=eyeRightY + eyeRightH / 2,
                               radiusPixel=eyeRightH / 2,
                               blinkCriterion=settingsDict['blink'].value /
                               100.0,
                               blurSize=settingsDict['blur'].value,
                               filterSize=settingsDict['filter'].value))

        #update the dots given the latest image
        for i in range(len(dotList)):
            dotList[i].update(img=image,
                              fid=dotList[0],
                              blinkCriterion=settingsDict['blink'].value /
                              100.0,
                              blurSize=settingsDict['blur'].value,
                              filterSize=settingsDict['filter'].value)
            # print 'ok'

        #some post-processing
        blinkHappened = False
        saccadeHappened = False
        if len(dotList) == 3:
            if dotList[0].lost:
                dotList = []
                print 'fid lost'
            elif (dotList[1].lostCount > 30) or (dotList[2].lostCount > 30):
                print "lost lots"
                if (not dotList[1].blinkHappened) and (
                        not dotList[2].blinkHappened
                ):  #only reset if not blinking
                    dotList = []
            elif dotList[1].blinkHappened and dotList[2].blinkHappened:
                blinkHappened = True
            else:
                #compute gaze location to check for saccades
                xCoefLeft, xCoefRight, yCoefLeft, yCoefRight = calibrationCoefs
                if dotList[1].lost:  #left missing, use right
                    xLoc = xCoefRight[0] + xCoefRight[1] * dotList[
                        2].x2 + xCoefRight[2] * dotList[2].y2 + xCoefRight[
                            3] * dotList[2].y2 * dotList[2].x2
                    yLoc = yCoefRight[0] + yCoefRight[1] * dotList[
                        2].x2 + yCoefRight[2] * dotList[2].y2 + yCoefRight[
                            3] * dotList[2].y2 * dotList[2].x2
                elif dotList[2].lost:  #right missing, use left
                    xLoc = xCoefLeft[0] + xCoefLeft[1] * dotList[
                        1].x2 + xCoefLeft[2] * dotList[1].y2 + xCoefLeft[
                            3] * dotList[2].y2 * dotList[1].x2
                    yLoc = yCoefLeft[0] + yCoefLeft[1] * dotList[
                        1].x2 + yCoefLeft[2] * dotList[1].y2 + yCoefLeft[
                            3] * dotList[2].y2 * dotList[1].x2
                elif dotList[1].lost and dotList[
                        2].lost:  #both missing, use last
                    xLoc = lastLocs[0]
                    yLoc = lastLocs[1]
                else:  #both present, use average
                    xLocLeft = xCoefLeft[0] + xCoefLeft[1] * dotList[
                        1].x2 + xCoefLeft[2] * dotList[1].y2 + xCoefLeft[
                            3] * dotList[1].y2 * dotList[1].x2
                    yLocLeft = yCoefLeft[0] + yCoefLeft[1] * dotList[
                        1].x2 + yCoefLeft[2] * dotList[1].y2 + yCoefLeft[
                            3] * dotList[1].y2 * dotList[1].x2
                    xLocRight = xCoefRight[0] + xCoefRight[1] * dotList[
                        2].x2 + xCoefRight[2] * dotList[2].y2 + xCoefRight[
                            3] * dotList[2].y2 * dotList[2].x2
                    yLocRight = yCoefRight[0] + yCoefRight[1] * dotList[
                        2].x2 + yCoefRight[2] * dotList[2].y2 + yCoefRight[
                            3] * dotList[2].y2 * dotList[2].x2
                    xLoc = (xLocLeft + xLocRight) / 2.0
                    yLoc = (yLocLeft + yLocRight) / 2.0
                if None not in lastLocs:
                    locDiff = (((xLoc - lastLocs[0])**2) +
                               ((yLoc - lastLocs[1])**2))**.5
                    if doneCalibration:
                        saccadeCriterion = settingsDict['saccade'].value
                    else:
                        saccadeCriterion = settingsDict[
                            'saccade0'].value / 100.0
                    if locDiff > saccadeCriterion:
                        saccadeHappened = True
                lastLocs = [xLoc, yLoc]
                if queueDataToParent:
                    qFrom.put([
                        'eyeData',
                        [
                            str.format('{0:.3f}', imageTime), xLoc, yLoc,
                            dotlist[1].radius2, dotlist[2].radius2,
                            saccadeHappened, blinkHappened, dotList[1].lost,
                            dotList[2].lost, dotList[1].blinkHappened,
                            dotList[2].blinkHappened
                        ]
                    ])

        #play sounds as necessary
        if doSounds:
            if (not saccadeSound.stillPlaying()) and (
                    not blinkSound.stillPlaying()):
                if blinkHappened:
                    blinkSound.play()
                elif saccadeHappened:
                    saccadeSound.play()

        #do drawing
        if previewDownsize != 1:
            image = cv2.resize(image,
                               dsize=previewWindow.size,
                               interpolation=cv2.INTER_NEAREST)
        image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
        if clickingForDots:
            if clickingForFid:
                if definingFidFinderBox:
                    cv2.circle(image, (fidFinderBoxX, fidFinderBoxY),
                               fidFinderBoxSize,
                               color=(255, 0, 0, 255),
                               thickness=1)
        for dot in dotList:
            ellipse = ((dot.ellipse[0][0] / previewDownsize,
                        dot.ellipse[0][1] / previewDownsize),
                       (dot.ellipse[1][0] / previewDownsize,
                        dot.ellipse[1][1] / previewDownsize), dot.ellipse[2])
            if dot.blinkHappened or dot.lost:
                dotColor = (0, 0, 255, 255)
            else:
                dotColor = (0, 255, 0, 255)
            cv2.ellipse(image, ellipse, color=dotColor, thickness=1)
        image = numpy.rot90(image)
        previewWindowArray[:, :, 0:3] = image
        frameToFrameTimeList.append(imageTime - lastTime)
        lastTime = imageTime
        displayLagList.append(getTime() - imageTime)
        if len(displayLagList) > 30:
            displayLagList.pop(0)
            frameToFrameTimeList.pop(0)
        clickableTextDict['lag'].valueText = str(
            int(numpy.median(displayLagList) * 1000))
        clickableTextDict['lag'].updateSurf()
        clickableTextDict['f2f'].valueText = str(
            int(numpy.median(frameToFrameTimeList) * 1000))
        clickableTextDict['f2f'].updateSurf()
        for clickableText in clickableTextDict:
            clickableTextDict[clickableText].draw(previewWindowSurf)
        previewWindow.refresh()
        thisRefreshTime = getTime()
        # print (thisRefreshTime - lastRefreshTime)*1000
        lastRefreshTime = thisRefreshTime
        if (sdl2.SDL_GetWindowFlags(settingsWindow.window)
                & sdl2.SDL_WINDOW_SHOWN):
            sdl2.ext.fill(settingsWindowSurf.contents,
                          sdl2.pixels.SDL_Color(r=0, g=0, b=0, a=255))
            for setting in settingsDict:
                settingsDict[setting].draw(settingsWindowSurf)
            settingsWindow.refresh()

        #calibration stuff
        if calibrating:
            if not calibrationChild.qFrom.empty():
                message = calibrationChild.qFrom.get()
                if message == 'startQueing':
                    queueDataToCalibrationChild = True
                elif message[0] == 'stopQueing':
                    calibrationStopTime = message[1]
                    checkCalibrationStopTime = True
                elif message[0] == 'calibrationCoefs':
                    calibrationCoefs = message[1]
                    calibrating = False
                    doneCalibration = True
                    calibrationChild.stop()
                    del calibrationChild
                    lastLocs = []
                    qFrom.put(['calibrationComplete', message])
                    queueDataToParent = True
                else:
                    print message
            if checkCalibrationStopTime:
                if imageTime > calibrationStopTime:
                    queueDataToCalibrationChild = False
                    calibrationChild.qTo.put('doneQueing')
                    checkCalibrationStopTime = False
            if queueDataToCalibrationChild:
                if len(dotList) > 0:
                    calibrationChild.qTo.put([
                        imageTime, dotList[1].x2, dotList[1].y2, dotList[2].x2,
                        dotList[2].y2
                    ])
示例#19
0
 def pump(self):
     sdl2.SDL_PumpEvents()
     self._window.refresh()
示例#20
0
def labjackChildFunction(qTo,
                         qFrom,
                         windowSize=[200, 200],
                         windowPosition=[0, 0]):
    import sdl2
    import sdl2.ext
    import sys
    import time
    try:
        import appnope
        appnope.nope()
    except:
        pass

    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    window = sdl2.ext.Window("labjack",
                             size=windowSize,
                             position=windowPosition,
                             flags=sdl2.SDL_WINDOW_SHOWN)
    windowID = sdl2.SDL_GetWindowID(window.window)
    windowSurf = sdl2.SDL_GetWindowSurface(window.window)
    sdl2.ext.fill(windowSurf.contents,
                  sdl2.pixels.SDL_Color(r=255, g=255, b=255, a=255))
    window.refresh()

    for i in range(10):
        sdl2.SDL_PumpEvents()  #to show the windows

    import u3

    d = u3.U3()
    d.configU3()
    d.getCalibrationData()
    d.configAnalog(u3.FIO0)
    checkForNextZeroTime = False
    checkForTrialNextZeroTime = False

    def exitSafely():
        d.close()
        sys.exit()

    sendTriggers = False
    while True:
        if sendTriggers:
            if not checkForNextZeroTime:
                temp = d.getAIN(0)
                # print temp
                if temp > .5:  #photosensor surpasses criterion
                    d.getFeedback(u3.BitStateWrite(IONumber=8, State=1))
                    nextZeroTime = time.time(
                    ) + .010  #wait 10ms before setting the state back to zero, giving the amp time to pick it up
                    checkForNextZeroTime = True
            else:
                if time.time() >= nextZeroTime:  #time to turn the bit back off
                    d.getFeedback(u3.BitStateWrite(IONumber=8, State=0))
                    checkForNextZeroTime = False
            if checkForTrialNextZeroTime:
                if time.time() >= trialNextZeroTime:
                    d.getFeedback(u3.BitStateWrite(IONumber=9, State=0))
                    checkForTrialNextZeroTime = False
        if not qTo.empty():
            message = qTo.get()
            if message == 'quit':
                exitSafely()
            elif message == 'trialDone':
                sendTriggers = False
                checkForTrialNextZeroTime = False
                checkForNextZeroTime = False
                d.getFeedback(u3.BitStateWrite(
                    IONumber=8, State=0))  #should be zero, but just in case...
                d.getFeedback(u3.BitStateWrite(
                    IONumber=9, State=0))  #should be zero, but just in case...
            elif message == 'trialStart':
                sendTriggers = True
                d.getFeedback(u3.BitStateWrite(IONumber=9, State=1))
                trialNextZeroTime = time.time(
                ) + .010  #wait 10ms before setting the state back to zero, giving the amp time to pick it up
                checkForTrialNextZeroTime = True
        sdl2.SDL_PumpEvents()
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_WINDOWEVENT:
                if (event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE):
                    exitSafely()
示例#21
0
def eyelinkChildFunction(qTo,
                         qFrom,
                         windowSize=[200, 200],
                         windowPosition=[0, 0],
                         stimDisplayRes=[1920, 1080],
                         calibrationDisplaySize=[1920, 1080],
                         calibrationDotSize=10,
                         eyelinkIp='100.1.1.1',
                         edfFileName='temp.edf',
                         edfPath='./_Data/temp.edf',
                         saccadeSoundFile='_Stimuli/stop.wav',
                         blinkSoundFile='_Stimuli/stop.wav'):
    import sdl2
    import sdl2.ext
    import math
    import OpenGL.GL as gl
    import sdl2.sdlmixer
    import pylink
    import numpy
    import sys
    import shutil
    import subprocess
    import time
    import os
    import array
    from PIL import Image
    from PIL import ImageDraw
    try:
        import appnope
        appnope.nope()
    except:
        pass

    byteify = lambda x, enc: x.encode(enc)

    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    window = sdl2.ext.Window("eyelink",
                             size=windowSize,
                             position=windowPosition,
                             flags=sdl2.SDL_WINDOW_SHOWN)
    windowID = sdl2.SDL_GetWindowID(window.window)
    windowSurf = sdl2.SDL_GetWindowSurface(window.window)
    sdl2.ext.fill(windowSurf.contents,
                  sdl2.pixels.SDL_Color(r=0, g=0, b=0, a=255))
    window.refresh()

    for i in range(10):
        sdl2.SDL_PumpEvents()  #to show the windows

    sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
    sdl2.sdlmixer.Mix_OpenAudio(44100, sdl2.sdlmixer.MIX_DEFAULT_FORMAT, 2,
                                1024)

    class Sound:
        def __init__(self, fileName):
            self.sample = sdl2.sdlmixer.Mix_LoadWAV(
                sdl2.ext.compat.byteify(fileName, "utf-8"))
            self.started = False

        def play(self):
            self.channel = sdl2.sdlmixer.Mix_PlayChannel(-1, self.sample, 0)
            self.started = True

        def stillPlaying(self):
            if self.started:
                if sdl2.sdlmixer.Mix_Playing(self.channel):
                    return True
                else:
                    self.started = False
                    return False
            else:
                return False

    saccadeSound = Sound(saccadeSoundFile)
    blinkSound = Sound(blinkSoundFile)

    def exitSafely():
        if 'eyelink' in locals():
            if eyelink.isRecording() == 0:
                eyelink.stopRecording()
            eyelink.setOfflineMode()
            eyelink.closeDataFile()
            eyelink.receiveDataFile(edfFileName, 'temp.edf')
            eyelink.close()
            if os.path.isfile('temp.edf'):
                shutil.move('temp.edf', edfPath)
                # if os.path.isfile(edfPath):
                # 	subprocess.call('./edf2asc -y ./'+edfPath,shell=True)
        sys.exit(
        )  #process gets hung here if called when showing images from eyelink

    pylink.setDriftCorrectSounds('off', 'off', 'off')
    pylink.setCalibrationSounds('off', 'off', 'off')

    edfPath = './_Data/temp.edf'  #temporary default location, to be changed later when ID is established
    done = False
    while not done:
        try:
            # print '\neyelink: Attempting to connect to eyelink (check that wifi is off!)'
            eyelink = pylink.EyeLink(eyelinkIp)
            done = True
        except:
            while not qTo.empty():
                message = qTo.get()
                if message == 'quit':
                    exitSafely()
                else:
                    qTo.put(message)

    # print 'eyelink: connected'
    eyelink.sendCommand(
        'select_parser_configuration 0'
    )  # 0--> standard (cognitive); 1--> sensitive (psychophysical)
    # eyelink.sendCommand('sample_rate 500')
    eyelink.setLinkEventFilter("SACCADE,BLINK,FIXATION,LEFT,RIGHT")
    eyelink.openDataFile(edfFileName)
    eyelink.sendCommand(
        "screen_pixel_coords =  %d %d %d %d" %
        (stimDisplayRes[0] / 2 - calibrationDisplaySize[0] / 2,
         stimDisplayRes[1] / 2 - calibrationDisplaySize[1] / 2,
         stimDisplayRes[0] / 2 + calibrationDisplaySize[0] / 2,
         stimDisplayRes[1] / 2 + calibrationDisplaySize[1] / 2))
    eyelink.sendMessage("DISPLAY_COORDS  0 0 %d %d" %
                        (stimDisplayRes[0], stimDisplayRes[1]))
    eyelink.sendCommand("saccade_velocity_threshold = 60")
    eyelink.sendCommand("saccade_acceleration_threshold = 19500")

    class EyeLinkCoreGraphicsPySDL2(pylink.EyeLinkCustomDisplay):
        def __init__(self):
            # self.__target_beep__ = Sound('_Stimuli/type.wav')
            # self.__target_beep__done__ = Sound('qbeep.wav')
            # self.__target_beep__error__ = Sound('error.wav')
            if sys.byteorder == 'little':
                self.byteorder = 1
            else:
                self.byteorder = 0
            self.imagebuffer = array.array('I')
            self.pal = None
            self.__img__ = None

        def record_abort_hide(self):
            pass

        def play_beep(self, beepid):
            pass
            # if beepid == pylink.DC_TARG_BEEP or beepid == pylink.CAL_TARG_BEEP:
            # 	self.__target_beep__.play()
            # elif beepid == pylink.CAL_ERR_BEEP or beepid == pylink.DC_ERR_BEEP:
            # 	self.__target_beep__error__.play()
            # else:#	CAL_GOOD_BEEP or DC_GOOD_BEEP
            # 	self.__target_beep__done__.play()
        def clear_cal_display(self):
            # # print 'clear_cal_display'
            qFrom.put('clearCalDisplay')

        def setup_cal_display(self):
            # # print 'setup_cal_display'
            qFrom.put('setupCalDisplay')

        def exit_cal_display(self):
            # # print 'exit_cal_display'
            qFrom.put('exitCalDisplay')

        def erase_cal_target(self):
            # # print 'erase_cal_target'
            qFrom.put('eraseCalTarget')

        def draw_cal_target(self, x, y):
            # # print 'draw_cal_target'
            qFrom.put(['drawCalTarget', x, y])

        def setup_image_display(self, width, height):
            # # print 'eyelink: setup_image_display'
            self.img_size = (width, height)
            return (0)

        def exit_image_display(self):
            # # print 'eyelink: exit_image_display'
            pass

        def image_title(self, text):
            # # print 'eyelink: image_title'
            pass

        def set_image_palette(self, r, g, b):
            # # print 'eyelink: set_image_palette'
            self.imagebuffer = array.array('I')
            sz = len(r)
            i = 0
            self.pal = []
            while i < sz:
                rf = int(b[i])
                gf = int(g[i])
                bf = int(r[i])
                if self.byteorder:
                    self.pal.append((rf << 16) | (gf << 8) | (bf))
                else:
                    self.pal.append(
                        (bf << 24) | (gf << 16) | (rf << 8))  #for mac
                i = i + 1

        def draw_image_line(self, width, line, totlines, buff):
            # # print 'eyelink: draw_image_line'
            i = 0
            while i < width:
                if buff[i] >= len(self.pal):
                    buff[i] = len(self.pal) - 1
                self.imagebuffer.append(self.pal[buff[i] & 0x000000FF])
                i = i + 1
            if line == totlines:
                img = Image.fromstring('RGBX', (width, totlines),
                                       self.imagebuffer.tostring())
                img = img.convert('RGBA')
                self.__img__ = img.copy()
                self.__draw__ = ImageDraw.Draw(self.__img__)
                self.draw_cross_hair(
                )  #inherited method, calls draw_line and draw_losenge
                qFrom.put([
                    'image',
                    numpy.array(
                        self.__img__.resize([
                            self.__img__.size[0] * 4, self.__img__.size[1] * 4
                        ], Image.BICUBIC))
                ])
                self.__img__ = None
                self.__draw__ = None
                self.imagebuffer = array.array('I')

        def getColorFromIndex(self, colorindex):
            if colorindex == pylink.CR_HAIR_COLOR: return (255, 255, 255, 255)
            elif colorindex == pylink.PUPIL_HAIR_COLOR:
                return (255, 255, 255, 255)
            elif colorindex == pylink.PUPIL_BOX_COLOR:
                return (0, 255, 0, 255)
            elif colorindex == pylink.SEARCH_LIMIT_BOX_COLOR:
                return (255, 0, 0, 255)
            elif colorindex == pylink.MOUSE_CURSOR_COLOR:
                return (255, 0, 0, 255)
            else:
                return (0, 0, 0, 0)

        def draw_line(self, x1, y1, x2, y2, colorindex):
            # # print 'eyelink: draw_line'
            if x1 < 0: x1 = 0
            if x2 < 0: x2 = 0
            if y1 < 0: y1 = 0
            if y2 < 0: y2 = 0
            if x1 > self.img_size[0]: x1 = self.img_size[0]
            if x2 > self.img_size[0]: x2 = self.img_size[0]
            if y1 > self.img_size[1]: y1 = self.img_size[1]
            if y2 > self.img_size[1]: y2 = self.img_size[1]
            imr = self.__img__.size
            x1 = int((float(x1) / float(self.img_size[0])) * imr[0])
            x2 = int((float(x2) / float(self.img_size[0])) * imr[0])
            y1 = int((float(y1) / float(self.img_size[1])) * imr[1])
            y2 = int((float(y2) / float(self.img_size[1])) * imr[1])
            color = self.getColorFromIndex(colorindex)
            self.__draw__.line([(x1, y1), (x2, y2)], fill=color)
            return 0

        def draw_lozenge(self, x, y, width, height, colorindex):
            # # print 'eyelink: draw_lozenge'
            color = self.getColorFromIndex(colorindex)
            imr = self.__img__.size
            x = int((float(x) / float(self.img_size[0])) * imr[0])
            width = int((float(width) / float(self.img_size[0])) * imr[0])
            y = int((float(y) / float(self.img_size[1])) * imr[1])
            height = int((float(height) / float(self.img_size[1])) * imr[1])
            if width > height:
                rad = height / 2
                self.__draw__.line([(x + rad, y), (x + width - rad, y)],
                                   fill=color)
                self.__draw__.line([(x + rad, y + height),
                                    (x + width - rad, y + height)],
                                   fill=color)
                clip = (x, y, x + height, y + height)
                self.__draw__.arc(clip, 90, 270, fill=color)
                clip = ((x + width - height), y, x + width, y + height)
                self.__draw__.arc(clip, 270, 90, fill=color)
            else:
                rad = width / 2
                self.__draw__.line([(x, y + rad), (x, y + height - rad)],
                                   fill=color)
                self.__draw__.line([(x + width, y + rad),
                                    (x + width, y + height - rad)],
                                   fill=color)
                clip = (x, y, x + width, y + width)
                self.__draw__.arc(clip, 180, 360, fill=color)
                clip = (x, y + height - width, x + width, y + height)
                self.__draw__.arc(clip, 360, 180, fill=color)
            return 0

        def get_mouse_state(self):
            # pos = pygame.mouse.get_pos()
            # state = pygame.mouse.get_pressed()
            # return (pos,state[0])
            pass

        def get_input_key(self):
            ky = []
            while not qTo.empty():
                message = qTo.get()
                # print 'eyelink: '
                # print message
                if message == 'button':
                    ky.append(
                        pylink.KeyInput(32, 0)
                    )  #button translated to space keypress (for drift correct)
                # if message=='quit':
                # 	# print 'received message to exit'
                # 	exitSafely()
                # el
                elif message[0] == 'keycode':
                    keysym = message[1]
                    keycode = keysym.sym
                    if keycode == sdl2.SDLK_F1: keycode = pylink.F1_KEY
                    elif keycode == sdl2.SDLK_F2: keycode = pylink.F2_KEY
                    elif keycode == sdl2.SDLK_F3: keycode = pylink.F3_KEY
                    elif keycode == sdl2.SDLK_F4: keycode = pylink.F4_KEY
                    elif keycode == sdl2.SDLK_F5: keycode = pylink.F5_KEY
                    elif keycode == sdl2.SDLK_F6: keycode = pylink.F6_KEY
                    elif keycode == sdl2.SDLK_F7: keycode = pylink.F7_KEY
                    elif keycode == sdl2.SDLK_F8: keycode = pylink.F8_KEY
                    elif keycode == sdl2.SDLK_F9: keycode = pylink.F9_KEY
                    elif keycode == sdl2.SDLK_F10: keycode = pylink.F10_KEY
                    elif keycode == sdl2.SDLK_PAGEUP: keycode = pylink.PAGE_UP
                    elif keycode == sdl2.SDLK_PAGEDOWN:
                        keycode = pylink.PAGE_DOWN
                    elif keycode == sdl2.SDLK_UP:
                        keycode = pylink.CURS_UP
                    elif keycode == sdl2.SDLK_DOWN:
                        keycode = pylink.CURS_DOWN
                    elif keycode == sdl2.SDLK_LEFT:
                        keycode = pylink.CURS_LEFT
                    elif keycode == sdl2.SDLK_RIGHT:
                        keycode = pylink.CURS_RIGHT
                    elif keycode == sdl2.SDLK_BACKSPACE:
                        keycode = ord('\b')
                    elif keycode == sdl2.SDLK_RETURN:
                        keycode = pylink.ENTER_KEY
                    elif keycode == sdl2.SDLK_ESCAPE:
                        keycode = pylink.ESC_KEY
                    elif keycode == sdl2.SDLK_TAB:
                        keycode = ord('\t')
                    elif keycode == pylink.JUNK_KEY:
                        keycode = 0
                    ky.append(pylink.KeyInput(keycode, keysym.mod))
            return ky

    customDisplay = EyeLinkCoreGraphicsPySDL2()
    pylink.openGraphicsEx(customDisplay)
    newGazeTarget = False
    gazeTarget = numpy.array(calibrationDisplaySize) / 2.0
    gazeTargetCriterion = calibrationDotSize
    doSounds = False
    reportSaccades = False
    reportBlinks = False
    lastMessageTime = time.time()
    lastStartBlinkTime = time.time()
    while True:
        sdl2.SDL_PumpEvents()
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_WINDOWEVENT:
                if (event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE):
                    exitSafely()
        if not qTo.empty():
            message = qTo.get()
            if message == 'quit':
                exitSafely()
            elif message[0] == 'edfPath':
                edfPath = message[1]
            elif message[0] == 'doSounds':
                doSounds = message[1]
            elif message[0] == 'reportSaccades':
                reportSaccades = message[1]
            elif message[0] == 'reportBlinks':
                reportBlinks = message[1]
            elif message[0] == 'sendMessage':
                eyelink.sendMessage(message[1])
            elif message[0] == 'doDriftCorrect':
                # print 'eyelink: drift correct requested'
                if eyelink.isRecording() == 0:
                    eyelink.stopRecording()
                try:
                    location = message[1]
                    error = eyelink.doDriftCorrect(location[0], location[1], 0,
                                                   1)
                    # print error
                    # print 'eyelink: drift correct attempted'
                    if error != 27:
                        qFrom.put('driftCorrectComplete')
                    else:
                        qFrom.put('doCalibration')
                except:
                    qFrom.put('doCalibration')
            elif message == 'startRecording':
                # print 'eyelink: received message to begin recording'
                eyelink.startRecording(
                    1, 1, 1, 1
                )  #this retuns immediately takes 10-30ms to actually kick in on the tracker
                while not (eyelink.isRecording() == 0):
                    pass
                    # print eyelink.isRecording()
                qFrom.put('recordingStarted')
            elif message[0] == 'newGazeTarget':
                # # print message
                newGazeTarget = True
                gazeTarget = numpy.array(message[1])
                gazeTargetCriterion = numpy.array(message[2])
                # # print message
                # # print 'waiting for gaze confirmation'
            elif message[0] == 'acceptTrigger':
                eyelink.accept_trigger()
            elif message == 'doCalibration':
                doSounds = False
                if eyelink.isRecording() == 0:
                    eyelink.stopRecording()
                eyelink.doTrackerSetup()
                # # print 'calComplete'
                qFrom.put('calibrationComplete')
        if eyelink.isRecording(
        ) == 0:  #stupid, I know, but eyelink.isRecording() returns 0 if it *is* indeed recording!
            eyeData = eyelink.getNextData()
            # if eyeData==pylink.SAMPLE_TYPE:
            # 	eyeSample = eyelink.getFloatData()
            # 	gaze = None
            # 	if eyeSample.isRightSample():
            # 		gaze = eyeSample.getRightEye().getGaze()
            # 	elif eyeSample.isLeftSample():
            # 		gaze = eyeSample.getLeftEye().getGaze()
            # 	if gaze!=None:
            # 		if gaze[0]!=-32768.0:
            # 			gazeDistFromGazeTarget = numpy.linalg.norm(numpy.array(gaze)-gazeTarget)
            # 			if newGazeTarget:
            # 				if gazeDistFromGazeTarget<gazeTargetCriterion:
            # 					# print ['gazeTargetMet',gaze,gazeTargetCriterion,gazeTarget,gazeDistFromGazeTarget]
            # 					qFrom.put(['gazeTargetMet',gazeTarget])
            # 					newGazeTarget = False
            # 				else:
            # 					qFrom.put(['gazeTargetNotMet',gazeTarget])
            # 					# print ['gazeTargetNotMet',gaze,gazeTarget,gazeDistFromGazeTarget,gazeTargetCriterion]
            if eyeData == pylink.ENDSACC:
                eyeSample = eyelink.getFloatData()
                gazeStartTime = eyeSample.getStartTime()
                gazeStart = eyeSample.getStartGaze()
                gazeEnd = eyeSample.getEndGaze()
                # # print ['eyelink: saccade',gazeStart,gazeEnd]
                if (gazeStart[0] != -32768.0) & (gazeEnd[0] != -32768.0):
                    gazeDistFromGazeTarget = numpy.linalg.norm(
                        numpy.array(gazeEnd) - gazeTarget)
                    if gazeDistFromGazeTarget < 1000:
                        if newGazeTarget:
                            # # print [gazeDistFromGazeTarget,gazeTargetCriterion,gazeTarget,gazeEnd]
                            if gazeDistFromGazeTarget < gazeTargetCriterion:
                                # # print ['gazeTargetMet',gazeEnd,gazeTargetCriterion,gazeTarget,gazeDistFromGazeTarget]
                                qFrom.put([
                                    'gazeTargetMet', gazeTarget, gazeStartTime
                                ])
                                newGazeTarget = False
                                # # print 'gazeTargetMet'
                        elif gazeDistFromGazeTarget > gazeTargetCriterion:
                            if reportSaccades:
                                qFrom.put(['gazeTargetLost', gazeTarget])
                                # # print ['gazeTargetLost',gazeTarget]
                            if (not saccadeSound.stillPlaying()) and (
                                    not blinkSound.stillPlaying()):
                                if doSounds:
                                    saccadeSound.play()
            elif eyeData == pylink.STARTBLINK:
                # 	lastStartBlinkTime = time.time()
                # elif eyeData==pylink.ENDBLINK:
                # 	if (time.time()-lastStartBlinkTime)>.1:
                if reportBlinks:
                    qFrom.put('blink')
                    # # print 'eyelink: blink'
                if (not saccadeSound.stillPlaying()) and (
                        not blinkSound.stillPlaying()):
                    if doSounds:
                        #blinkSound.play()
                        qFrom.put('blink')
示例#22
0
    def handle_input(self):
        app = self.app
        # get and store mouse state
        # (store everything in parent app object so stuff can access it easily)
        mx, my = ctypes.c_int(0), ctypes.c_int(0)
        mouse = sdl2.mouse.SDL_GetMouseState(mx, my)
        app.left_mouse = bool(mouse & sdl2.SDL_BUTTON(sdl2.SDL_BUTTON_LEFT))
        app.middle_mouse = bool(mouse
                                & sdl2.SDL_BUTTON(sdl2.SDL_BUTTON_MIDDLE))
        app.right_mouse = bool(mouse & sdl2.SDL_BUTTON(sdl2.SDL_BUTTON_RIGHT))
        mx, my = int(mx.value), int(my.value)
        # if mouse hasn't moved since init, disregard SDL_GetMouseState
        if self.mouse_has_moved:
            app.mouse_x, app.mouse_y = mx, my
        elif mx != 0 or my != 0:
            self.mouse_has_moved = True
        # relative mouse move state
        mdx, mdy = ctypes.c_int(0), ctypes.c_int(0)
        sdl2.mouse.SDL_GetRelativeMouseState(mdx, mdy)
        if self.mouse_has_moved:
            app.mouse_dx, app.mouse_dy = int(mdx.value), int(mdy.value)
        if app.mouse_dx != 0 or app.mouse_dy != 0:
            app.keyboard_editing = False
            # dragging a dialog?
            if app.left_mouse and self.ui.active_dialog in self.ui.hovered_elements:
                self.ui.active_dialog.update_drag(app.mouse_dx, app.mouse_dy)
        # get keyboard state so later we can directly query keys
        ks = sdl2.SDL_GetKeyboardState(None)
        # get modifier states
        self.shift_pressed, self.alt_pressed, self.ctrl_pressed = False, False, False
        if ks[sdl2.SDL_SCANCODE_LSHIFT] or ks[sdl2.SDL_SCANCODE_RSHIFT]:
            self.shift_pressed = True
        if ks[sdl2.SDL_SCANCODE_LALT] or ks[sdl2.SDL_SCANCODE_RALT]:
            self.alt_pressed = True
        if ks[sdl2.SDL_SCANCODE_LCTRL] or ks[sdl2.SDL_SCANCODE_RCTRL]:
            self.ctrl_pressed = True
        # macOS: treat command as interchangeable with control, is this kosher?
        if platform.system() == 'Darwin' and (ks[sdl2.SDL_SCANCODE_LGUI]
                                              or ks[sdl2.SDL_SCANCODE_RGUI]):
            self.ctrl_pressed = True
        if app.capslock_is_ctrl and ks[sdl2.SDL_SCANCODE_CAPSLOCK]:
            self.ctrl_pressed = True
        # pack mods into a tuple to save listing em all out repeatedly
        mods = self.shift_pressed, self.alt_pressed, self.ctrl_pressed
        # get controller state
        if self.gamepad:
            self.gamepad_left_x = sdl2.SDL_JoystickGetAxis(
                self.gamepad, sdl2.SDL_CONTROLLER_AXIS_LEFTX) / 32768
            self.gamepad_left_y = sdl2.SDL_JoystickGetAxis(
                self.gamepad, sdl2.SDL_CONTROLLER_AXIS_LEFTY) / -32768
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_QUIT:
                app.should_quit = True
            elif event.type == sdl2.SDL_WINDOWEVENT:
                if event.window.event == sdl2.SDL_WINDOWEVENT_RESIZED:
                    # test window we create on init to detect resolution makes
                    # SDL think we've resized main app window on first tick!
                    if app.updates > 0:
                        app.resize_window(event.window.data1,
                                          event.window.data2)
            elif event.type == sdl2.SDL_JOYBUTTONDOWN:
                if not app.gw.paused and app.gw.player:
                    app.gw.player.button_pressed(event.jbutton.button)
            elif event.type == sdl2.SDL_JOYBUTTONUP:
                if not app.gw.paused and app.gw.player:
                    self.app.gw.player.button_unpressed(event.jbutton.button)
            elif event.type == sdl2.SDL_KEYDOWN:
                keysym = self.get_keysym(event)
                # if console is up, pass input to it
                if self.ui.console.visible:
                    self.ui.console.handle_input(keysym, *mods)
                # same with dialog box
                elif self.ui.active_dialog and self.ui.active_dialog is self.ui.keyboard_focus_element:
                    self.ui.active_dialog.handle_input(keysym, *mods)
                    # bail, process no further input
                    #sdl2.SDL_PumpEvents()
                    #return
                # handle text input if text tool is active
                elif self.ui.selected_tool is self.ui.text_tool and self.ui.text_tool.input_active:
                    self.ui.text_tool.handle_keyboard_input(keysym, *mods)
                # see if there's a function for this bind and run it
                else:
                    flist = self.get_bind_functions(keysym, *mods)
                    for f in flist:
                        # don't run any command whose menu bar item's dimmed / not allowed (ie wrong mode)
                        if self.is_command_function_allowed(f):
                            f()
                    # if game mode active, pass to world as well as any binds
                    if self.app.game_mode:
                        self.app.gw.handle_input(event, *mods)
            # for key up events, use the same binds but handle them special case
            # TODO: once there are enough key up events, figure out a more
            # elegant way than this
            elif event.type == sdl2.SDL_KEYUP:
                keysym = self.get_keysym(event)
                if self.app.game_mode:
                    self.app.gw.handle_input(event, *mods)
                # dismiss selector popup
                flist = self.get_bind_functions(keysym, *mods)
                if not flist:
                    pass
                elif self.ui.active_dialog:
                    # keyup shouldn't have any special meaning in a dialog
                    pass
                elif self.BIND_game_grab in flist:
                    if self.app.game_mode and not self.ui.active_dialog and self.app.gw.player:
                        self.app.gw.player.button_unpressed(0)
                        return
                elif self.BIND_toggle_picker in flist:
                    # ..but only for default hold-to-show setting
                    if self.ui.popup_hold_to_show:
                        self.ui.popup.hide()
                elif self.BIND_select_or_paint in flist:
                    app.keyboard_editing = True
                    if not self.ui.selected_tool is self.ui.text_tool and not self.ui.text_tool.input_active:
                        self.app.cursor.finish_paint()
            #
            # mouse events aren't handled by bind table for now
            #
            elif event.type == sdl2.SDL_MOUSEWHEEL:
                ui_wheeled = self.ui.wheel_moved(event.wheel.y)
                if not ui_wheeled:
                    if self.app.can_edit:
                        if event.wheel.y > 0:
                            # only zoom in should track towards cursor
                            app.camera.zoom(-self.wheel_zoom_amount,
                                            towards_cursor=True)
                        elif event.wheel.y < 0:
                            app.camera.zoom(self.wheel_zoom_amount)
                    else:
                        self.app.gw.mouse_wheeled(event.wheel.y)
            elif event.type == sdl2.SDL_MOUSEBUTTONUP:
                # "consume" input if UI handled it
                ui_unclicked = self.ui.unclicked(event.button.button)
                if ui_unclicked:
                    sdl2.SDL_PumpEvents()
                    return
                if self.app.game_mode:
                    self.app.gw.unclicked(event.button.button)
                # LMB up: finish paint for most tools, end select drag
                if event.button.button == sdl2.SDL_BUTTON_LEFT:
                    if self.ui.selected_tool is self.ui.select_tool and self.ui.select_tool.selection_in_progress:
                        self.ui.select_tool.finish_select(
                            self.shift_pressed, self.ctrl_pressed)
                    elif not self.ui.selected_tool is self.ui.text_tool and not self.ui.text_tool.input_active:
                        app.cursor.finish_paint()
            elif event.type == sdl2.SDL_MOUSEBUTTONDOWN:
                ui_clicked = self.ui.clicked(event.button.button)
                # don't register edit commands if a menu is up
                if ui_clicked or self.ui.menu_bar.active_menu_name or self.ui.active_dialog:
                    sdl2.SDL_PumpEvents()
                    if self.app.game_mode:
                        self.app.gw.last_click_on_ui = True
                    return
                # pass clicks through to game world
                if self.app.game_mode:
                    if not ui_clicked:
                        self.app.gw.clicked(event.button.button)
                # LMB down: start text entry, start select drag, or paint
                elif event.button.button == sdl2.SDL_BUTTON_LEFT:
                    if not self.ui.active_art:
                        return
                    elif self.ui.selected_tool is self.ui.text_tool:
                        # text tool: only start entry if click is outside popup
                        if not self.ui.text_tool.input_active and \
                         not self.ui.popup in self.ui.hovered_elements:
                            self.ui.text_tool.start_entry()
                    elif self.ui.selected_tool is self.ui.select_tool:
                        # select tool: accept clicks if they're outside the popup
                        if not self.ui.select_tool.selection_in_progress and \
                            (not self.ui.keyboard_focus_element or \
                               (self.ui.keyboard_focus_element is self.ui.popup and \
                                not self.ui.popup in self.ui.hovered_elements)):
                            self.ui.select_tool.start_select()
                    else:
                        app.cursor.start_paint()
                elif event.button.button == sdl2.SDL_BUTTON_RIGHT:
                    if self.app.ui.active_art:
                        self.ui.quick_grab()
        # none of the below applies to cases where a dialog is up
        if self.ui.active_dialog:
            sdl2.SDL_PumpEvents()
            return
        # directly query keys we don't want affected by OS key repeat delay
        # TODO: these are hard-coded for the moment, think of a good way
        # to expose this functionality to the key bind system
        def pressing_up(ks):
            return ks[sdl2.SDL_SCANCODE_W] or ks[sdl2.SDL_SCANCODE_UP] or ks[
                sdl2.SDL_SCANCODE_KP_8]

        def pressing_down(ks):
            return ks[sdl2.SDL_SCANCODE_S] or ks[sdl2.SDL_SCANCODE_DOWN] or ks[
                sdl2.SDL_SCANCODE_KP_2]

        def pressing_left(ks):
            return ks[sdl2.SDL_SCANCODE_A] or ks[sdl2.SDL_SCANCODE_LEFT] or ks[
                sdl2.SDL_SCANCODE_KP_4]

        def pressing_right(ks):
            return ks[sdl2.SDL_SCANCODE_D] or ks[
                sdl2.SDL_SCANCODE_RIGHT] or ks[sdl2.SDL_SCANCODE_KP_6]

        # prevent camera move if: console is up, text input is active, editing
        # is not allowed
        if self.shift_pressed and not self.alt_pressed and not self.ctrl_pressed and not self.ui.console.visible and not self.ui.text_tool.input_active and self.app.can_edit and self.ui.keyboard_focus_element is None:
            if pressing_up(ks):
                app.camera.pan(0, 1, True)
            if pressing_down(ks):
                app.camera.pan(0, -1, True)
            if pressing_left(ks):
                app.camera.pan(-1, 0, True)
            if pressing_right(ks):
                app.camera.pan(1, 0, True)
            if ks[sdl2.SDL_SCANCODE_X]:
                app.camera.zoom(-self.keyboard_zoom_amount,
                                keyboard=True,
                                towards_cursor=True)
            if ks[sdl2.SDL_SCANCODE_Z]:
                app.camera.zoom(self.keyboard_zoom_amount, keyboard=True)
        if self.app.can_edit and app.middle_mouse and (app.mouse_dx != 0
                                                       or app.mouse_dy != 0):
            app.camera.mouse_pan(app.mouse_dx, app.mouse_dy)
        # game mode: arrow keys and left gamepad stick move player
        if self.app.game_mode and not self.ui.console.visible and not self.ui.active_dialog and self.ui.keyboard_focus_element is None:
            if pressing_up(ks):
                # shift = move selected
                if self.shift_pressed and self.app.can_edit:
                    app.gw.move_selected(0, 1, 0)
                elif not self.ctrl_pressed and app.gw.player:
                    app.gw.player.move(0, 1)
            if pressing_down(ks):
                if self.shift_pressed and self.app.can_edit:
                    app.gw.move_selected(0, -1, 0)
                elif not self.ctrl_pressed and app.gw.player:
                    app.gw.player.move(0, -1)
            if pressing_left(ks):
                if self.shift_pressed and self.app.can_edit:
                    app.gw.move_selected(-1, 0, 0)
                elif not self.ctrl_pressed and app.gw.player:
                    app.gw.player.move(-1, 0)
            if pressing_right(ks):
                if self.shift_pressed and self.app.can_edit:
                    app.gw.move_selected(1, 0, 0)
                elif not self.ctrl_pressed and app.gw.player:
                    app.gw.player.move(1, 0)
            if abs(self.gamepad_left_x) > 0.15 and app.gw.player:
                app.gw.player.move(self.gamepad_left_x, 0)
            if abs(self.gamepad_left_y) > 0.15 and app.gw.player:
                app.gw.player.move(0, self.gamepad_left_y)
        sdl2.SDL_PumpEvents()
示例#23
0
def stamperChildFunction(qTo,
                         qFrom,
                         windowSize=[200, 200],
                         windowPosition=[0, 0],
                         windowColor=[255, 255, 255],
                         doBorder=True):
    import sdl2
    import sdl2.ext
    import sys
    import time
    try:
        import appnope
        appnope.nope()
    except:
        pass
    sdl2.SDL_Init(sdl2.SDL_INIT_TIMER)
    timeFreq = 1.0 / sdl2.SDL_GetPerformanceFrequency()
    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    if doBorder:
        flags = sdl2.SDL_WINDOW_SHOWN
    else:
        flags = sdl2.SDL_WINDOW_BORDERLESS | sdl2.SDL_WINDOW_SHOWN
    window = sdl2.ext.Window("pyStamper",
                             size=windowSize,
                             position=windowPosition,
                             flags=flags)
    windowID = sdl2.SDL_GetWindowID(window.window)
    windowSurf = sdl2.SDL_GetWindowSurface(window.window)
    red = sdl2.pixels.SDL_Color(r=255, g=0, b=0, a=255)
    green = sdl2.pixels.SDL_Color(r=0, g=255, b=0, a=255)
    black = sdl2.pixels.SDL_Color(r=0, g=0, b=0, a=255)
    white = sdl2.pixels.SDL_Color(r=255, g=255, b=255, a=255)
    if doBorder:
        sdl2.ext.fill(windowSurf.contents, green)
    else:
        sdl2.ext.fill(
            windowSurf.contents,
            sdl2.pixels.SDL_Color(r=windowColor[0],
                                  g=windowColor[1],
                                  b=windowColor[2],
                                  a=255))
    window.refresh()

    for i in range(10):
        sdl2.SDL_PumpEvents()  #to show the windows

    sdl2.SDL_Init(
        sdl2.SDL_INIT_JOYSTICK)  #uncomment if you want joystick input
    sdl2.SDL_JoystickOpen(0)  #uncomment if you want joystick input
    lostFocus = True
    lostColors = [red, black, red, white]
    lastRefreshTime = time.time()
    while True:
        if lostFocus and doBorder:
            if time.time() > (lastRefreshTime + (2.0 / 60)):
                sdl2.ext.fill(windowSurf.contents, lostColors[0])
                window.refresh()
                lostColors.append(lostColors.pop(0))
                lastRefreshTime = time.time()
        sdl2.SDL_PumpEvents()
        if not qTo.empty():
            message = qTo.get()
            if message == 'quit':
                sys.exit()
            elif message == 'raise':
                sdl2.SDL_RaiseWindow(window.window)
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_WINDOWEVENT:
                if event.window.windowID == windowID:
                    if (event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE):
                        qFrom.put({
                            'type': 'key',
                            'time': event.window.timestamp * timeFreq,
                            'value': 'escape'
                        })
                        sys.exit()
                    elif event.window.event == sdl2.SDL_WINDOWEVENT_FOCUS_LOST:
                        lostFocus = True
                    elif event.window.event == sdl2.SDL_WINDOWEVENT_FOCUS_GAINED:
                        lostFocus = False
                        if doBorder:
                            sdl2.ext.fill(windowSurf.contents, green)
                            window.refresh()
            else:
                message = {}
                if event.type == sdl2.SDL_KEYDOWN:
                    message['type'] = 'key'
                    message['time'] = event.key.timestamp * timeFreq
                    message['value'] = sdl2.SDL_GetKeyName(
                        event.key.keysym.sym).lower()
                    message['keysym'] = event.key.keysym
                    qFrom.put(message)
                elif event.type == sdl2.SDL_JOYAXISMOTION:
                    message['type'] = 'axis'
                    message['axis'] = event.jaxis.axis
                    message['time'] = event.jaxis.timestamp * timeFreq
                    message['value'] = event.jaxis.value
                    qFrom.put(message)
                elif event.type == sdl2.SDL_JOYBUTTONDOWN:
                    message['type'] = 'button'
                    message['time'] = event.jbutton.timestamp * timeFreq
                    message['value'] = event.jbutton.button
                    qFrom.put(message)