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