예제 #1
0
    def __init__(self, mounted_on_desk, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Remove current exit key (make it available for customised setting)
        # HACK: There is no 'NONE_KEY' defined, so setting the escape key to 0
        #       could cause undefined behaviour, as it is undocomunted. During
        #       the tests, this setting did not activate any of the keys, so it
        #       is a working work-around. (At least on Arch Linux)
        bge.logic.setExitKey(0)

        # Place the window
        window_command = ['sleep 1']
        window_command.append('wmctrl -r :ACTIVE: '
                              '-e 0,{},{},{},{}'.format(WINDOW_DISPLAY_X,
                                                        WINDOW_DISPLAY_Y,
                                                        WINDOW_RESOLUTION_X,
                                                        WINDOW_RESOLUTION_Y))
        if WINDOW_FULL_SCREEN:
            window_command.append('wmctrl -r :ACTIVE: -b add,fullscreen')

        Popen(args   = ' && '.join(window_command),
              shell  = True,
              stdin  = PIPE,
              stderr = PIPE,
              universal_newlines=True)

        # Create folder structures if they don't exists yet
        makedirs(INT_TEMPORARY_FOLDER,  exist_ok=True)
        makedirs(INT_PERMANENT_FOLDER,  exist_ok=True)
        makedirs(INT_TEMP_SAVE_FOLDER,  exist_ok=True)
        makedirs(INT_AUTO_SAVE_FOLDER,  exist_ok=True)

        ## Start input-daemon
        #self._lines_queue = Queue()
        #def get_input():
        #    print('start')
        #    for line in iter(stdin.readline, ''):
        #        print('try')
        #        self._lines_queue.put(line)
        #    print('stop')
        #    stdin.close()

        #Thread(name   = 'inputd',
        #       target = get_input).start()
        #self._should_restart   = False
        #self._should_shut_down = False

        try:
            # Create connection
            self._connection = Connection(this_host=COMM_THIS_HOST,
                                          this_port=COMM_THIS_PORT,
                                          buffer_size=BUFFER_SIZE,
                                          device=COMM_DEVICE_NAME)
            self._connection.connect(other_host=COMM_OTHER_HOST,
                                     other_port=COMM_OTHER_PORT)
        # If connection is not imported
        except NameError:
            pass
        # Create a new instance of the leap-motion controller
        self._leap_controller = leap_controller = Leap.Controller()
        # Create a new instance of the oculus-rift controller
        self._rift_controller = oculus.OculusRiftDK2(head_factor =RIFT_MULTIPLIER,
                                                     head_shift_y=RIFT_POSITION_SHIFT_Y,
                                                     head_shift_z=RIFT_POSITION_SHIFT_Z)

        # Enable HMD optimisation
        if MOUNTED_ON_HEAD:
            leap_controller.set_policy(Leap.Controller.POLICY_OPTIMIZE_HMD)
        ## Enable circle gesture
        #leap_controller.enable_gesture(Leap.Gesture.TYPE_CIRCLE)
        ## Configure circle gesture
        #leap_controller.config.set("Gesture.Circle.MinRadius", 100.0)
        #leap_controller.config.set("Gesture.Circle.MinArc", radians(359))
        ## Configure swipe gesture
        #leap_controller.config.set("Gesture.Swipe.MinLength", 200.0)
        #leap_controller.config.set("Gesture.Swipe.MinVelocity", 750)
        #leap_controller.config.save()

        # Create a reference to the blender scene
        self._blender_scene = blender_scene = bge.logic.getCurrentScene()
        bge.logic.addScene(OBJ_HUD_SCENE, 1)
        # HUD scene has to be set up
        self._preprocess = True

        # Make references to blender objects
        self._camera = blender_scene.active_camera
        self._origo  = blender_scene.objects[OBJ_GLOBAL]

        # Create hands
        self._hands = Hands(self._prototype_creator(OBJ_PROTOTYPE_FINGER))

        # Create surface blender object from prototype and
        # store its reference inside a Surface instance
        # HACK: Surface arguments should be protoype_creator methods, instead of
        #       actual objects, but right now, prototyping the surface object
        #       with its armature and all bones are not copying.. or something
        #       like that..
        self._surface = Surface(blender_scene.objects[OBJ_PROTOTYPE_SURFACE],
                                blender_scene.objects[OBJ_PROTOTYPE_VERTEX_ALL],
                                COLOR_GEOMETRY_DARK)

        # TODO: fake casted shadow with negative lamp:
        #       https://www.youtube.com/watch?v=iJUlqwKEdVQ

        # HACK: yuck.. this is getting out of hands now :(:(:(
        self._vertex_origo = blender_scene.objects[OBJ_PROTOTYPE_VERTEX_ALL]

        # EXPERIMENTAL
        self._armature_control = blender_scene.objects[OBJ_ARMATURE_CONTROL]
        self._armature         = blender_scene.objects[OBJ_ARMATURE]
        self._geometry         = blender_scene.objects[OBJ_GEOMETRY]
        # EXPERIMENTAL

        # Set position setter
        # If DESK
        if mounted_on_desk:
            self._positioner = self._positioner_on_desk
            self._selector   = self._select_right_hand_on_desk
        # If HEAD
        else:
            self._positioner = self._positioner_on_head
            self._selector   = self._select_right_hand_on_head

        # Last time saved
        self._auto_save_time = self._origo[PROP_TEXT_TIMER]
예제 #2
0
class Application(CallbackManager):

    # NOTE: local->global: http://blenderartists.org/forum/archive/index.php/t-180690.html

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    @property
    def text(self):
        return self._text

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    @property
    def hands(self):
        return self._hands

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    @property
    def surface(self):
        return self._surface

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    @property
    def vertex_origo(self):
        return self._vertex_origo


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def __init__(self, mounted_on_desk, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Remove current exit key (make it available for customised setting)
        # HACK: There is no 'NONE_KEY' defined, so setting the escape key to 0
        #       could cause undefined behaviour, as it is undocomunted. During
        #       the tests, this setting did not activate any of the keys, so it
        #       is a working work-around. (At least on Arch Linux)
        bge.logic.setExitKey(0)

        # Place the window
        window_command = ['sleep 1']
        window_command.append('wmctrl -r :ACTIVE: '
                              '-e 0,{},{},{},{}'.format(WINDOW_DISPLAY_X,
                                                        WINDOW_DISPLAY_Y,
                                                        WINDOW_RESOLUTION_X,
                                                        WINDOW_RESOLUTION_Y))
        if WINDOW_FULL_SCREEN:
            window_command.append('wmctrl -r :ACTIVE: -b add,fullscreen')

        Popen(args   = ' && '.join(window_command),
              shell  = True,
              stdin  = PIPE,
              stderr = PIPE,
              universal_newlines=True)

        # Create folder structures if they don't exists yet
        makedirs(INT_TEMPORARY_FOLDER,  exist_ok=True)
        makedirs(INT_PERMANENT_FOLDER,  exist_ok=True)
        makedirs(INT_TEMP_SAVE_FOLDER,  exist_ok=True)
        makedirs(INT_AUTO_SAVE_FOLDER,  exist_ok=True)

        ## Start input-daemon
        #self._lines_queue = Queue()
        #def get_input():
        #    print('start')
        #    for line in iter(stdin.readline, ''):
        #        print('try')
        #        self._lines_queue.put(line)
        #    print('stop')
        #    stdin.close()

        #Thread(name   = 'inputd',
        #       target = get_input).start()
        #self._should_restart   = False
        #self._should_shut_down = False

        try:
            # Create connection
            self._connection = Connection(this_host=COMM_THIS_HOST,
                                          this_port=COMM_THIS_PORT,
                                          buffer_size=BUFFER_SIZE,
                                          device=COMM_DEVICE_NAME)
            self._connection.connect(other_host=COMM_OTHER_HOST,
                                     other_port=COMM_OTHER_PORT)
        # If connection is not imported
        except NameError:
            pass
        # Create a new instance of the leap-motion controller
        self._leap_controller = leap_controller = Leap.Controller()
        # Create a new instance of the oculus-rift controller
        self._rift_controller = oculus.OculusRiftDK2(head_factor =RIFT_MULTIPLIER,
                                                     head_shift_y=RIFT_POSITION_SHIFT_Y,
                                                     head_shift_z=RIFT_POSITION_SHIFT_Z)

        # Enable HMD optimisation
        if MOUNTED_ON_HEAD:
            leap_controller.set_policy(Leap.Controller.POLICY_OPTIMIZE_HMD)
        ## Enable circle gesture
        #leap_controller.enable_gesture(Leap.Gesture.TYPE_CIRCLE)
        ## Configure circle gesture
        #leap_controller.config.set("Gesture.Circle.MinRadius", 100.0)
        #leap_controller.config.set("Gesture.Circle.MinArc", radians(359))
        ## Configure swipe gesture
        #leap_controller.config.set("Gesture.Swipe.MinLength", 200.0)
        #leap_controller.config.set("Gesture.Swipe.MinVelocity", 750)
        #leap_controller.config.save()

        # Create a reference to the blender scene
        self._blender_scene = blender_scene = bge.logic.getCurrentScene()
        bge.logic.addScene(OBJ_HUD_SCENE, 1)
        # HUD scene has to be set up
        self._preprocess = True

        # Make references to blender objects
        self._camera = blender_scene.active_camera
        self._origo  = blender_scene.objects[OBJ_GLOBAL]

        # Create hands
        self._hands = Hands(self._prototype_creator(OBJ_PROTOTYPE_FINGER))

        # Create surface blender object from prototype and
        # store its reference inside a Surface instance
        # HACK: Surface arguments should be protoype_creator methods, instead of
        #       actual objects, but right now, prototyping the surface object
        #       with its armature and all bones are not copying.. or something
        #       like that..
        self._surface = Surface(blender_scene.objects[OBJ_PROTOTYPE_SURFACE],
                                blender_scene.objects[OBJ_PROTOTYPE_VERTEX_ALL],
                                COLOR_GEOMETRY_DARK)

        # TODO: fake casted shadow with negative lamp:
        #       https://www.youtube.com/watch?v=iJUlqwKEdVQ

        # HACK: yuck.. this is getting out of hands now :(:(:(
        self._vertex_origo = blender_scene.objects[OBJ_PROTOTYPE_VERTEX_ALL]

        # EXPERIMENTAL
        self._armature_control = blender_scene.objects[OBJ_ARMATURE_CONTROL]
        self._armature         = blender_scene.objects[OBJ_ARMATURE]
        self._geometry         = blender_scene.objects[OBJ_GEOMETRY]
        # EXPERIMENTAL

        # Set position setter
        # If DESK
        if mounted_on_desk:
            self._positioner = self._positioner_on_desk
            self._selector   = self._select_right_hand_on_desk
        # If HEAD
        else:
            self._positioner = self._positioner_on_head
            self._selector   = self._select_right_hand_on_head

        # Last time saved
        self._auto_save_time = self._origo[PROP_TEXT_TIMER]


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def reset_view(self):
        orientation = Matrix(((1.0, 0.0, 0.0),
                              (0.0, 1.0, 0.0),
                              (0.0, 0.0, 1.0)))
        self._armature_control.worldOrientation = orientation
        self._armature.worldOrientation = orientation
        self._vertex_origo.worldScale = 1, 1, 1
        self._surface.update()


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def save(self):
        # Save created mesh
        file_path = INT_TEMP_SAVE_FILE.format(datetime.now())
        save_to_file(path=file_path, data=self._surface.serialise())
        print('[OKAY] file has been saved to:', file_path)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def load(self):
        try:
            file_path = join(INT_TEMP_SAVE_FOLDER,
                             next(reversed(sorted(listdir(INT_TEMP_SAVE_FOLDER)))))
            self._surface.deserialise(load_from_file(file_path))
            print('[OKAY] file has been loaded from:', file_path)
        except StopIteration:
            print('[FAIL] there is no file in:', INT_TEMP_SAVE_FOLDER)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def auto_save(self):
        current_time = self._origo[PROP_TEXT_TIMER]
        if self._auto_save_time + INT_AUTO_SAVE_INTERVAL <= current_time:
            # Update last-time checked value
            self._auto_save_time = current_time
            # Save created mesh
            save_to_file(path=INT_AUTO_SAVE_FILE,
                         data=self._surface.serialise())
            print('[OKAY] file has been auto-saved to:', INT_AUTO_SAVE_FILE)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def recover_from_auto_save(self):
        self._auto_save_time = self._origo[PROP_TEXT_TIMER]
        self._surface.deserialise(load_from_file(INT_AUTO_SAVE_FILE))
        print('[OKAY] file has been recovered from:', INT_AUTO_SAVE_FILE)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def __call__(self):
        # HACK: The ugliest hack I've ever done...
        if self._preprocess:
            try:
                # Set HUD scene
                self._blender_overlay_scene = bge.logic.getSceneList()[1]
                # Stop preprocessing loops
                self._preprocess = False
                # Set text and its details
                text_1st_obj = self._blender_overlay_scene.objects[OBJ_TEXT_FIRST]
                text_nth_obj = self._blender_overlay_scene.objects[OBJ_TEXT_OTHER]
                text_1st_obj.resolution = text_nth_obj.resolution = 10
                # Create HUD messaging system
                self._text = Text(text_first_object=text_1st_obj,
                                  text_other_object=text_nth_obj,
                                  time_getter=lambda: self._origo[PROP_TEXT_TIMER],
                                  interval=INT_TEXT_INTERVAL)
            except IndexError:
                return

        # Try to create backup
        self.auto_save()

        #try:
        #    print('input:', self._lines_queue.get_nowait())
        #except Empty:
        #    pass

        # Ste states
        self.set_states(restart=COMM_RUNNING,
                        escape =APP_RUNNING)
        # If user pressed the space bar => restart game
        if bge.logic.keyboard.events[ESCAPE_KEY] == JUST_ACTIVATED:
            self.set_states(escape=APP_ESCAPED)
        elif bge.logic.keyboard.events[SPACE_KEY] == JUST_ACTIVATED:
            self.set_states(restart=COMM_RESTART)
        elif bge.logic.keyboard.events[R_KEY] == JUST_ACTIVATED:
            self.recover_from_auto_save()
        elif bge.logic.keyboard.events[S_KEY] == JUST_ACTIVATED:
            self.save()
        elif bge.logic.keyboard.events[L_KEY] == JUST_ACTIVATED:
            self.load()
        elif bge.logic.keyboard.events[HOME_KEY] == JUST_ACTIVATED:
            self.reset_view()
        elif bge.logic.keyboard.events[BACK_SPACE_KEY] == JUST_ACTIVATED:
            self._text.clear()

        # Get current values of oculus-rift
        rift_frame = self._rift_controller.frame()
        # Get current values of the leap-motion
        leap_frame = self._leap_controller.frame()

        # Set camera position and orientation
        self._camera.worldPosition = rift_frame.position
        self._camera.worldOrientation = \
            RIFT_ORIENTATION_SHIFT*Quaternion(rift_frame.orientation)

        # If leap was unable to get a proper frame
        if not leap_frame.is_valid:
            return print('(leap) Invalid frame', file=stderr)

        # Update messaging system
        self._text.update()

        # If leap was able to get the frame set finger positions
        selector   = self._selector
        positioner = self._positioner
        try:
            self.execute_all_callbacks()
            #circle_cw = circle_ccw = False
            #for gesture in leap_frame.gestures():
            #    if (gesture.type is Leap.Gesture.TYPE_CIRCLE and
            #        gesture.is_valid and
            #        gesture.state is Leap.Gesture.STATE_STOP):
            #            circle =  Leap.CircleGesture(gesture)
            #            if (circle.pointable.direction.angle_to(circle.normal) <= Leap.PI/2):
            #                circle_ccw=True
            #            else:
            #                circle_cw=True
            #self._hands.set_states(circle_cw=circle_cw,
            #                       circle_ccw=circle_ccw)
            for leap_hand in leap_frame.hands:
                hand = selector(leap_hand.is_right)
                # TODO: do I still need to set the states of these?
                hand.set_states(hand=hand,
                                #circle_cw=circle_cw,
                                #circle_ccw=circle_ccw,
                                leap_hand=leap_hand)
                for finger in leap_hand.fingers:
                    # TODO: positioner(*finger.tip_position) => leaking memory and never returns
                    hand.finger_by_leap(finger.type()).position = positioner(finger.tip_position)
                hand.execute_all_callbacks()
            self._hands.execute_all_callbacks()
        except EscapeApplication:
            self._clean_up()
            bge.logic.endGame()
        except RestartApplication:
            self._clean_up()
            bge.logic.restartGame()

        # TODO: use `leap_frame.images` as background

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _select_right_hand_on_head(self, is_left):
        return self._hands.left if is_left else self._hands.right


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _select_right_hand_on_desk(self, is_right):
        return self._hands.right if is_right else self._hands.left


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _positioner_on_head(self, position):
        # The USB cable is on the right side and
        # the indicator light is on the top
        return (position[0] * -LEAP_MULTIPLIER,
                position[1] *  LEAP_MULTIPLIER - 10,
                position[2] * -LEAP_MULTIPLIER + 10)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _positioner_on_desk(self, position):
        # The USB cable is on the right side and
        # the indicator light is at the back
        return (position[0] *  LEAP_MULTIPLIER,
                position[2] * -LEAP_MULTIPLIER,
                position[1] *  LEAP_MULTIPLIER -10)#-25)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _prototype_creator(self, prototype):
        def creator(**preferences):
            object = self._blender_scene.addObject(prototype, OBJ_GLOBAL)
            for preference, value in preferences.items():
                setattr(object, preference, value)
            return object
        return creator


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _clean_up(self):
        # Close connection if app is paired
        try:
            self.connection.stop()
        except AttributeError:
            pass
        # Save created mesh
        self.save()