diff --git a/src/morse/builder/creator.py b/src/morse/builder/creator.py index e342f5987..6095f2ff9 100644 --- a/src/morse/builder/creator.py +++ b/src/morse/builder/creator.py @@ -76,30 +76,3 @@ def __init__(self, name="ActuatorCreator", classpath="morse.core.actuator.Actuat blendname=None): ComponentCreator.__init__(self, name, 'actuators', blendname) self.properties(Component_Tag = True, classpath = classpath) - -# helpers - -def get_properties_str(name): - """ Returns the Game properties of the Blender object represented by the name - - get_properties_str('Sick') gives - laser_range = 30.0, Component_Tag = True, scan_window = 180.0, - Visible_arc = True, resolution = 0.25, - classpath = 'morse.sensors.sick.LaserScannerClass' - """ - obj = bpymorse.get_object(name) - properties_dictionary = get_properties(obj) - return ", ".join(["%s = %s"%(pname, properties_dictionary[pname]) \ - for pname in properties_dictionary]) - -def get_properties(obj): - import json - properties_dictionary = {} - properties = obj.game.properties - for name in properties.keys(): - properties_dictionary[name] = properties[name].value - if properties[name].type == 'TIMER': - properties_dictionary[name] = "timer(%f)"%properties_dictionary[name] - elif type(properties_dictionary[name]) is str: - properties_dictionary[name] = json.dumps(properties_dictionary[name]) - return properties_dictionary diff --git a/src/morse/builder/environment.py b/src/morse/builder/environment.py index bf6e80289..e802520bf 100644 --- a/src/morse/builder/environment.py +++ b/src/morse/builder/environment.py @@ -1,6 +1,7 @@ import logging; logger = logging.getLogger("morsebuilder." + __name__) import os import json +import morse.builder.setup from morse.builder.morsebuilder import * from morse.builder.abstractcomponent import Configuration from morse.core.morse_time import TimeStrategies @@ -269,7 +270,7 @@ def create(self, name=None): # define 'Scene_Script_Holder' as the blender object of Enrivonment if not 'Scene_Script_Holder' in bpymorse.get_objects(): # Add the necessary objects - base = Component('props', 'basics') + morse.builder.setup.init_morse() # Set Scene_Script_Holder as core Environment object self.set_blender_object(bpymorse.get_object('Scene_Script_Holder')) diff --git a/src/morse/builder/setup.py b/src/morse/builder/setup.py new file mode 100644 index 000000000..26af91d87 --- /dev/null +++ b/src/morse/builder/setup.py @@ -0,0 +1,353 @@ +# usage: blender -P {file} +import os, sys, subprocess + +def ext_exec(cmd, python=None): + if not python: + python = 'python%i.%i'%(sys.version_info.major, sys.version_info.minor) + return subprocess.getoutput('%s -c"%s"' % (python, cmd) ) + +def fix_python_path(python=None): + pythonpath = ext_exec("import os,sys;print(os.pathsep.join(sys.path))") + sys.path.extend(pythonpath.split(os.pathsep)) + +# add system Python ``sys.path`` to Blender Python ``sys.path`` +# allow us to import ``morse`` package (installed in system Python path) +fix_python_path() + +import bpy +from morse.builder import AbstractComponent +from morse.builder.bpymorse import * +from mathutils import Vector, Euler + +def init_morse(): + setup_scene() + setup_basics() + finalize() + +def finalize(): + camera = bpy.data.objects['CameraFP'] + camera.data.clip_end = 1000 + bpy.context.scene.camera = camera + # see the texture in realtime (in the 3D viewport) + set_viewport('TEXTURED', 10000) + +def setup_scene(scene=None): + """ Setup the scene """ + if not scene and bpy: + scene = bpy.context.scene + # Set Game mode + scene.render.engine = 'BLENDER_GAME' + # make sure OpenGL shading language shaders (GLSL) is the + # material mode to use for rendering + # scene.game_settings.material_mode = 'GLSL' + # Set the unit system to use for button display (in edit mode) to metric + scene.unit_settings.system = 'METRIC' + # Select the type of Framing to Extend, + # Show the entire viewport in the display window, + # viewing more horizontally or vertically. + scene.game_settings.frame_type = 'EXTEND' + # Set the color at the horizon to dark azure + scene.world.horizon_color = (0.05, 0.22, 0.4) + # Display framerate and profile information of the simulation + scene.game_settings.show_framerate_profile = True + scene.game_settings.show_mouse = True + scene.render.resolution_x = 320 + scene.render.resolution_y = 240 + scene.render.fps = 25 + +def setup_basics(): + base = AbstractComponent(category='props', filename='basics_wo_logic') + base.append_meshes(['CameraID_text', 'Compass', 'HUD_plane', 'Keys_text', 'Screen', 'Screen_frame', 'Title_text']) + # CAMERA : CameraFP + bpy.ops.object.add(type='CAMERA', location=Vector((6.0, 0.0, 4.0)), rotation=Euler((1.57, 0.0, 1.57), 'XYZ')) + bpy.context.object.name = 'CameraFP' + bpy.context.object.game.physics_type = 'STATIC' + bpy.context.object.hide_render = False + properties(bpy.context.object, Sensitivity=0.001, Speed=0.1) + game = bpy.context.object.game + add_actuator(type='SCENE', name='Set_Camera') + game.actuators[-1].mode = "CAMERA" + game.actuators[-1].name = "Set_Camera" + add_controller(type='LOGIC_AND', name='cont') + game.controllers[-1].name = "cont" + game.controllers['cont'].link(actuator=game.actuators['Set_Camera']) + add_controller(type='PYTHON', name='Store degfault') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "view_camera.store_default" + game.controllers[-1].name = "Store degfault" + add_controller(type='PYTHON', name='MouseLook') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "view_camera.rotate" + game.controllers[-1].name = "MouseLook" + add_controller(type='PYTHON', name='KeyboardMove') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "view_camera.move" + game.controllers[-1].name = "KeyboardMove" + add_sensor(type='ALWAYS', name='onLoad') + game.sensors[-1].name = "onLoad" + game.sensors['onLoad'].link(game.controllers['Store degfault']) + game.sensors['onLoad'].link(game.controllers['cont']) + add_sensor(type='MOUSE', name='Mouse') + game.sensors[-1].mouse_event = "MOVEMENT" + game.sensors[-1].name = "Mouse" + game.sensors['Mouse'].link(game.controllers['MouseLook']) + add_sensor(type='KEYBOARD', name='All_Keys') + game.sensors[-1].key = "NONE" + game.sensors[-1].name = "All_Keys" + game.sensors[-1].use_all_keys = True + game.sensors[-1].use_pulse_true_level = True + game.sensors['All_Keys'].link(game.controllers['KeyboardMove']) + game.sensors['All_Keys'].link(game.controllers['MouseLook']) + # MESH : CameraID_text + select_only(bpy.data.objects['CameraID_text']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = True + properties(bpy.context.object, Text="No camera selected") + game = bpy.context.object.game + # MESH : Compass + select_only(bpy.data.objects['Compass']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = False + properties(bpy.context.object, Display=True) + game = bpy.context.object.game + add_controller(type='PYTHON', name='Billboard') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "billboard.reset_rotation" + game.controllers[-1].name = "Billboard" + add_controller(type='PYTHON', name='Display') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "billboard.display" + game.controllers[-1].name = "Display" + add_sensor(type='ALWAYS', name='Always') + game.sensors[-1].name = "Always" + game.sensors[-1].use_pulse_true_level = True + game.sensors['Always'].link(game.controllers['Billboard']) + add_sensor(type='KEYBOARD', name='1') + game.sensors[-1].key = "ONE" + game.sensors[-1].modifier_key_1 = "LEFT_SHIFT" + game.sensors[-1].name = "1" + game.sensors['1'].link(game.controllers['Display']) + # MESH : HUD_plane + select_only(bpy.data.objects['HUD_plane']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = True + properties(bpy.context.object, Visible=False) + game = bpy.context.object.game + add_actuator(type='PROPERTY', name='Toggle') + game.actuators[-1].mode = "TOGGLE" + game.actuators[-1].name = "Toggle" + game.actuators[-1].object_property = "" + game.actuators[-1].property = "Visible" + game.actuators[-1].value = "" + add_actuator(type='VISIBILITY', name='Show') + game.actuators[-1].apply_to_children = True + game.actuators[-1].name = "Show" + game.actuators[-1].use_visible = True + add_actuator(type='VISIBILITY', name='Hide') + game.actuators[-1].apply_to_children = True + game.actuators[-1].use_visible = False + game.actuators[-1].name = "Hide" + add_controller(type='LOGIC_AND', name='And') + game.controllers[-1].name = "And" + game.controllers['And'].link(actuator=game.actuators['Toggle']) + add_controller(type='LOGIC_AND', name='And1') + game.controllers[-1].name = "And1" + game.controllers['And1'].link(actuator=game.actuators['Show']) + add_controller(type='LOGIC_NAND', name='Nand') + game.controllers[-1].name = "Nand" + game.controllers['Nand'].link(actuator=game.actuators['Hide']) + add_sensor(type='KEYBOARD', name='H_KEY') + game.sensors[-1].key = "H" + game.sensors[-1].name = "H_KEY" + game.sensors['H_KEY'].link(game.controllers['And']) + add_sensor(type='PROPERTY', name='Visible') + game.sensors[-1].name = "Visible" + game.sensors[-1].property = "Visible" + game.sensors[-1].value = "True" + game.sensors[-1].value_min = "True" + game.sensors['Visible'].link(game.controllers['And1']) + game.sensors['Visible'].link(game.controllers['Nand']) + # MESH : Keys_text + select_only(bpy.data.objects['Keys_text']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = True + properties(bpy.context.object, Text="HUD text") + game = bpy.context.object.game + add_controller(type='PYTHON', name='And') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "hud_text.change_text" + game.controllers[-1].name = "And" + add_sensor(type='ALWAYS', name='Keyboard') + game.sensors[-1].name = "Keyboard" + game.sensors['Keyboard'].link(game.controllers['And']) + # EMPTY : Scene_Script_Holder + bpy.ops.object.add(type='EMPTY', location=Vector((0.0, 0.0, 10.828))) + bpy.context.object.name = 'Scene_Script_Holder' + bpy.context.object.scale = Vector((0.675, 0.675, 0.675)) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = False + properties(bpy.context.object, paths_ok=True, UTMYOffset=0.0, UTMZOffset=0.0, environment_file="", UTMXOffset=0.0, Temperature="15.0") + game = bpy.context.object.game + add_actuator(type='GAME', name='Quit_sim') + game.actuators[-1].filename = "" + game.actuators[-1].mode = "QUIT" + game.actuators[-1].name = "Quit_sim" + add_actuator(type='GAME', name='Restart_sim') + game.actuators[-1].filename = "" + game.actuators[-1].mode = "RESTART" + game.actuators[-1].name = "Restart_sim" + add_controller(type='PYTHON', name='Path') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "setup_path.test" + game.controllers[-1].name = "Path" + game.controllers[-1].use_priority = True + game.controllers['Path'].link(actuator=game.actuators['Quit_sim']) + add_controller(type='PYTHON', name='Initialize') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "main.init" + game.controllers[-1].name = "Initialize" + game.controllers['Initialize'].link(actuator=game.actuators['Quit_sim']) + add_controller(type='PYTHON', name='Finalize') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "main.finish" + game.controllers[-1].name = "Finalize" + game.controllers['Finalize'].link(actuator=game.actuators['Quit_sim']) + add_controller(type='PYTHON', name='Switch_Camera') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "main.switch_camera" + game.controllers[-1].name = "Switch_Camera" + add_controller(type='LOGIC_AND', name='Fast_quit') + game.controllers[-1].name = "Fast_quit" + game.controllers['Fast_quit'].link(actuator=game.actuators['Quit_sim']) + add_controller(type='PYTHON', name='Admin') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "main.simulation_main" + game.controllers[-1].name = "Admin" + game.controllers['Admin'].link(actuator=game.actuators['Quit_sim']) + add_controller(type='PYTHON', name='Restart') + game.controllers[-1].mode = "MODULE" + game.controllers[-1].module = "main.restart" + game.controllers[-1].name = "Restart" + game.controllers['Restart'].link(actuator=game.actuators['Restart_sim']) + add_controller(type='PYTHON', name='Import_path_script') + game.controllers[-1].name = "Import_path_script" + add_sensor(type='ALWAYS', name='onLoad') + game.sensors[-1].name = "onLoad" + game.sensors['onLoad'].link(game.controllers['Path']) + add_sensor(type='PROPERTY', name='paths_ok') + game.sensors[-1].name = "paths_ok" + game.sensors[-1].property = "paths_ok" + game.sensors[-1].value = "True" + game.sensors[-1].value_min = "True" + game.sensors['paths_ok'].link(game.controllers['Initialize']) + add_sensor(type='KEYBOARD', name='ESC_KEY') + game.sensors[-1].key = "ESC" + game.sensors[-1].name = "ESC_KEY" + game.sensors['ESC_KEY'].link(game.controllers['Finalize']) + add_sensor(type='KEYBOARD', name='F9_KEY') + game.sensors[-1].key = "F9" + game.sensors[-1].name = "F9_KEY" + game.sensors['F9_KEY'].link(game.controllers['Switch_Camera']) + add_sensor(type='KEYBOARD', name='F12_KEY') + game.sensors[-1].key = "F12" + game.sensors[-1].name = "F12_KEY" + game.sensors['F12_KEY'].link(game.controllers['Fast_quit']) + add_sensor(type='ALWAYS', name='Constant') + game.sensors[-1].name = "Constant" + game.sensors[-1].use_pulse_true_level = True + game.sensors['Constant'].link(game.controllers['Admin']) + add_sensor(type='KEYBOARD', name='F11_KEY') + game.sensors[-1].key = "F11" + game.sensors[-1].name = "F11_KEY" + game.sensors['F11_KEY'].link(game.controllers['Restart']) + # MESH : Screen + select_only(bpy.data.objects['Screen']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = True + properties(bpy.context.object, DisplayCamera="CameraMain", Visible=False) + game = bpy.context.object.game + add_actuator(type='PROPERTY', name='Toggle') + game.actuators[-1].mode = "TOGGLE" + game.actuators[-1].name = "Toggle" + game.actuators[-1].object_property = "" + game.actuators[-1].property = "Visible" + game.actuators[-1].value = "" + add_actuator(type='VISIBILITY', name='Show') + game.actuators[-1].apply_to_children = True + game.actuators[-1].name = "Show" + game.actuators[-1].use_visible = True + add_actuator(type='VISIBILITY', name='Hide') + game.actuators[-1].apply_to_children = True + game.actuators[-1].use_visible = False + game.actuators[-1].name = "Hide" + add_controller(type='LOGIC_AND', name='And') + game.controllers[-1].name = "And" + game.controllers['And'].link(actuator=game.actuators['Toggle']) + add_controller(type='LOGIC_AND', name='And1') + game.controllers[-1].name = "And1" + game.controllers['And1'].link(actuator=game.actuators['Show']) + add_controller(type='LOGIC_NAND', name='Nand') + game.controllers[-1].name = "Nand" + game.controllers['Nand'].link(actuator=game.actuators['Hide']) + add_sensor(type='KEYBOARD', name='V_KEY') + game.sensors[-1].key = "V" + game.sensors[-1].name = "V_KEY" + game.sensors['V_KEY'].link(game.controllers['And']) + add_sensor(type='PROPERTY', name='Visible') + game.sensors[-1].name = "Visible" + game.sensors[-1].property = "Visible" + game.sensors[-1].value = "True" + game.sensors[-1].value_min = "True" + game.sensors['Visible'].link(game.controllers['And1']) + game.sensors['Visible'].link(game.controllers['Nand']) + # MESH : Screen_frame + select_only(bpy.data.objects['Screen_frame']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = True + game = bpy.context.object.game + # MESH : Title_text + select_only(bpy.data.objects['Title_text']) + bpy.context.object.game.physics_type = 'NO_COLLISION' + bpy.context.object.hide_render = True + properties(bpy.context.object, Text="MORSE keyboard shortcuts") + game = bpy.context.object.game + bpy.data.objects['Compass'].parent = bpy.data.objects['CameraFP'] + bpy.data.objects['HUD_plane'].parent = bpy.data.objects['CameraFP'] + bpy.data.objects['Screen'].parent = bpy.data.objects['CameraFP'] + bpy.data.objects['Keys_text'].parent = bpy.data.objects['HUD_plane'] + bpy.data.objects['Title_text'].parent = bpy.data.objects['HUD_plane'] + bpy.data.objects['CameraID_text'].parent = bpy.data.objects['Screen'] + bpy.data.objects['Screen_frame'].parent = bpy.data.objects['Screen'] + # text : setup_path.py + new_text() + text = get_last_text() + text.name = 'setup_path.py' + text_str = """import sys, os + +# Check that MORSE libraries are correctly installed +# Searches the PYTHONPATH variable for the required directories: $MORSE_ROOT and $MORSE_ROOT/morse/blender + +def test(contr): + print ("==============================") + print ("Welcome to the MORSE simulator") + print ("==============================") + blender_dir = 'morse/blender' + for dir in sys.path: + if os.path.exists(os.path.join(dir, "morse/blender/main.py")): + sys.path.append(os.path.join(dir, "morse/blender")) + sys.path.append(os.path.join(dir, "morse/blender/human_interaction")) + import imp + import morse.core.blenderapi + imp.reload(morse.core.blenderapi) + return + print ("MORSE ERROR: could not find the MORSE libraries. Please run 'morse check' from the command line to solve this issue.") + print ("Exiting the simulation!") + quitActuator = contr.actuators['Quit_sim'] + contr.activate(quitActuator) +""" + text.write(text_str) + text.use_module = True + +# test with: blender -P {file} +if __name__ == '__main__': + init_morse() diff --git a/tools/builder_generator.py b/tools/builder_generator.py new file mode 100644 index 000000000..fde9f5281 --- /dev/null +++ b/tools/builder_generator.py @@ -0,0 +1,186 @@ +# usage: blender file.blend -P builder_generator.py > file.py +import bpy, json + +# helpers (c/p following in a Blender Text editor, run it, look at your console) + +def select_only(obj): + bpy.ops.object.select_all(action='DESELECT') + obj.select = True + bpy.context.scene.objects.active = obj + +def roundv(v,r=3): + return tuple([round(e, r) for e in v]) + +def do_all(): + print("base = AbstractComponent(category='props', filename='basics_wo_logic')") + meshes = [o.name for o in bpy.data.objects if o.type == 'MESH'] + print("base.append_meshes(%s)"%repr(meshes)) + for obj in bpy.data.objects: + print("# %s : %s"%(obj.type, obj.name)) + if obj.type == 'MESH': + print("select_only(bpy.data.objects['%s'])"%obj.name) + else: + print("bpy.ops.object.add(type='%s', location=%s, rotation=%s)" % \ + (obj.type, repr(obj.location), repr(obj.rotation_euler))) + print("bpy.context.object.name = '%s'" % obj.name) + if obj.scale != (1,1,1): + print("bpy.context.object.scale = %s" % repr(obj.scale)) + + print("bpy.context.object.game.physics_type = '%s'" % obj.game.physics_type) + print("bpy.context.object.hide_render = %s" % obj.hide_render) + print_properties(obj) + print_all_logic(obj) + + # set children - parent relationship + for obj in bpy.data.objects: + for child in obj.children: + # child.parent = obj + print("bpy.data.objects['%s'].parent = bpy.data.objects['%s']" % \ + (child.name, obj.name) ) + + # set children - parent relationship + for text in bpy.data.texts: + print("# text : %s"%text.name) + print("new_text()") + print("text = get_last_text()") + print("text.name = '%s'" % text.name) + print("text_str = %s" % json.dumps(text.as_string()) ) + print("text.write(text_str)") + + +def get_properties(obj): + import json + map_prop = {} + properties = obj.game.properties + for name in properties.keys(): + map_prop[name] = properties[name].value + if properties[name].type == 'TIMER': + map_prop[name] = "timer(%f)"%map_prop[name] + elif type(map_prop[name]) is str: + map_prop[name] = json.dumps(map_prop[name]) + return map_prop + +def print_properties(obj): + """ Returns the Game properties of the Blender objects """ + map_prop = get_properties(obj) + if not map_prop: + return + str_prop = ", ".join(["%s=%s"%(pname, map_prop[pname]) \ + for pname in map_prop.keys()]) + print("properties(bpy.context.object, %s)" % str_prop) + +def print_all_logic(obj): + print("game = bpy.context.object.game") + for brick in obj.game.actuators: + print_logic(brick, 'actuator') + for brick in obj.game.controllers: + print_logic(brick, 'controller') + for act in brick.actuators: + print("game.controllers['%s'].link(actuator=game.actuators['%s'])" % \ + (brick.name, act.name) ) + for brick in obj.game.sensors: + print_logic(brick, 'sensor') + for ctr in brick.controllers: + print("game.sensors['%s'].link(game.controllers['%s'])" % \ + (brick.name, ctr.name) ) + +# map the default values of game logic bricks to filter the output +map_attr_default = { + 'default': { + '__module__': '', + 'type': '', + #'name': '', + 'show_expanded': '', + }, + 'sensor': { + 'default': { + 'frequency': 0, + 'invert': False, + 'use_level': False, + 'use_pulse_false_level': False, + 'use_pulse_true_level': False, + 'use_tap': False, + 'pin': False, + }, + 'PROPERTY': { + 'evaluation_type': 'PROPEQUAL', + 'property': '', + 'value': '', + 'value_max': '', + 'value_min': '', + }, + 'KEYBOARD': { + 'log': '', + 'modifier_key_1': 'NONE', + 'modifier_key_2': 'NONE', + 'target': '', + 'use_all_keys': False, + }, + 'MOUSE': { + 'use_pulse': False, + }, + }, + 'controller': { + 'default': { + 'use_priority': False, + 'states': 1, + }, + 'PYTHON': { + 'mode': 'SCRIPT', + 'module': '', + 'use_debug': False, + }, + }, + 'actuator': { + 'default': { + 'pin': False, + }, + 'VISIBILITY': { + 'apply_to_children': False, + 'use_occlusion': False, + }, + }, +} + +def print_logic(brick, sca): + print("add_%s(type='%s', name='%s')"%(sca, brick.type, brick.name)) + + for attr in dir(brick): + if attr in map_attr_default['default'].keys(): + continue # skip + value = getattr(brick, attr) + if attr in map_attr_default[sca]['default'].keys() and \ + value == map_attr_default[sca]['default'][attr]: + continue # skip default to save readibility + if brick.type in map_attr_default[sca] and \ + attr in map_attr_default[sca][brick.type].keys() and \ + value == map_attr_default[sca][brick.type][attr]: + continue # skip default to save readibility + if type(value).__name__ in ['int', 'float', 'bool']: + print("game.%ss[-1].%s = %s" % (sca, attr, str(value)) ) + if type(value).__name__ == 'str': + print("game.%ss[-1].%s = %s" % (sca, attr, json.dumps(value)) ) + +_header = """# usage: blender -P {file} +import os, sys, subprocess + +def ext_exec(cmd, python=None): + if not python: + python = 'python%i.%i'%(sys.version_info.major, sys.version_info.minor) + return subprocess.getoutput('%s -c"%s"' % (python, cmd) ) + +def fix_python_path(python=None): + pythonpath = ext_exec("import os,sys;print(os.pathsep.join(sys.path))") + sys.path.extend(pythonpath.split(os.pathsep)) + +fix_python_path() + +from morse.builder.bpymorse import * +from morse.builder import AbstractComponent +from mathutils import Vector, Euler +""" + +if __name__ == '__main__': + print(_header) + do_all() + print("\n\n# TODO remove the following lines (Blender output messages)\n\n")