1import logging; logger = logging.getLogger("morsebuilder." + __name__) 2from morse.builder import AbstractComponent, bpymorse 3from morse.core.exceptions import * 4 5class ComponentCreator(AbstractComponent): 6 _classpath = None 7 _blendname = None 8 9 APPEND_EMPTY = 0 10 USE_BLEND = 1 11 LINK_EXISTING_OBJECT = 2 12 13 def __init__(self, 14 name, 15 category, 16 action = APPEND_EMPTY, 17 blendfile = "", 18 blendobject = None, 19 make_morseable = True): 20 """ ComponentCreator constructor 21 22 This class allow to create simulation components from MORSE builder 23 scripts. It initially consists in an Empty object, to which you can 24 then add meshs of your choice. It adds automaticaly the logic (Always 25 sensor link to a Python controller). And set the default physics_type 26 to 'NO_COLLISION'. 27 28 :param name: (string) component name (used as Blender object name) 29 :param category: (string) one of ['actuators', 'sensors', 'robots'] 30 :param action: indicate what to do with the `blendfile` and 31 `blendobject` parameters. Must be one of [APPEND_EMPTY, USE_BLEND, 32 LINK_EXISTING_OBJECT]. 33 - If APPEND_EMPTY (default), a new Blender `Empty` is created and 34 `blendfile` and `blendobject` are ignored. 35 - If USE_BLEND, `blendfile` is treated as the path to a Blender file, 36 and if `blendobject` is also specified, the given object is 37 selected (otherwise, the last object selected in the Blender file 38 is returned). 39 - If LINK_EXISTING_OBJECT, `blendfile` is ignored and `blendobject` 40 is treated as the name of a Blender object which is already present 41 in the scene. 42 :param blendfile: (string, default:"") path to a Blender file (.blend) 43 containing meshes for the component. Must be in MORSE_RESOURCE_PATH. 44 :param blendobject: (string, default:None) Name of the Blender object 45 to use (cf above for details). 46 :param make_morseable: (boolean) Add Morse logic. Make it false 47 if you add some blend file which already contains the 48 necessary logic (default: True). 49 """ 50 AbstractComponent.__init__(self, filename=blendfile, category=category) 51 bpymorse.deselect_all() 52 if action == ComponentCreator.APPEND_EMPTY: 53 bpymorse.add_morse_empty() 54 elif action == ComponentCreator.USE_BLEND: 55 self.append_meshes() 56 if blendobject: 57 bpymorse.select_only(bpymorse.get_object(blendobject)) 58 elif action == ComponentCreator.LINK_EXISTING_OBJECT: 59 bpymorse.select_only(bpymorse.get_object(blendobject)) 60 61 obj = bpymorse.get_first_selected_object() 62 if name: 63 obj.name = name 64 self.basename = name 65 # no collision by default for components 66 obj.game.physics_type = 'NO_COLLISION' 67 self.set_blender_object(obj) 68 # Add MORSE logic 69 if make_morseable: 70 self.morseable() 71 72 self.properties(Component_Tag = True, classpath = self.__class__._classpath) 73 self.frequency(60) 74 75 def parent_root(self, objects): 76 # Parent the root objects with this Component 77 for child in objects: 78 if not child.parent: 79 child.matrix_parent_inverse.identity() 80 child.parent = self._bpy_object 81 82 def append_meshes(self, objects=None, component=None, prefix=None): 83 """ Append the objects to this component 84 85 Overloads :py:meth:`morse.builder.abstractcomponent.AbstractComponent.append_meshes` 86 87 :param objects: list of the objects names to append 88 :param component: component in which the objects are located 89 :return: list of the imported Blender objects 90 """ 91 imported_objects = AbstractComponent.append_meshes(self, objects, 92 component, prefix) 93 self.parent_root(imported_objects) 94 95 return imported_objects 96 97 def append_collada(self, component=None): 98 """ Append Collada objects to this component 99 100 Overloads :py:meth:`morse.builder.abstractcomponent.AbstractComponent.append_collada` 101 102 :param component: component in which the objects are located 103 :return: list of the imported Blender objects 104 """ 105 imported_objects = AbstractComponent.append_collada(self, component) 106 self.parent_root(imported_objects) 107 108 return imported_objects 109 110class SensorCreator(ComponentCreator): 111 def __init__(self, name = None, 112 action = ComponentCreator.APPEND_EMPTY, 113 make_morseable = True): 114 115 ComponentCreator.__init__(self, 116 name, 117 'sensors', 118 action, 119 blendfile = self.__class__._blendname, 120 make_morseable = make_morseable) 121 122 123class ActuatorCreator(ComponentCreator): 124 125 def __init__(self, name = None, 126 action = ComponentCreator.APPEND_EMPTY, 127 blendfile = None, 128 blendobject = None, 129 make_morseable = True): 130 131 if not blendfile: 132 blendfile = self.__class__._blendname 133 134 ComponentCreator.__init__(self, 135 name, 136 'actuators', 137 action, 138 blendfile, 139 blendobject, 140 make_morseable) 141