armory/blender/arm/props_exporter.py

290 lines
12 KiB
Python
Raw Normal View History

2017-08-21 15:36:21 +02:00
import os
import shutil
import arm.assets as assets
2017-11-20 14:32:36 +01:00
import arm.utils
2017-08-21 15:36:21 +02:00
import bpy
2017-10-21 16:09:06 +02:00
import stat
2018-03-22 21:43:22 +01:00
import subprocess
2018-03-24 11:55:10 +01:00
import webbrowser
2017-08-21 15:36:21 +02:00
from bpy.types import Menu, Panel, UIList
from bpy.props import *
2017-10-21 16:07:08 +02:00
def remove_readonly(func, path, excinfo):
os.chmod(path, stat.S_IWRITE)
func(path)
2018-12-05 10:36:36 +01:00
def update_gapi_custom(self, context):
2017-08-21 15:36:21 +02:00
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
2018-12-05 10:36:36 +01:00
def update_gapi_win(self, context):
if os.path.isdir(arm.utils.get_fp_build() + '/windows-build'):
shutil.rmtree(arm.utils.get_fp_build() + '/windows-build', onerror=remove_readonly)
2017-08-21 15:36:21 +02:00
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
def update_gapi_linux(self, context):
if os.path.isdir(arm.utils.get_fp_build() + '/linux-build'):
2017-10-21 16:07:08 +02:00
shutil.rmtree(arm.utils.get_fp_build() + '/linux-build', onerror=remove_readonly)
2017-08-21 15:36:21 +02:00
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
def update_gapi_mac(self, context):
if os.path.isdir(arm.utils.get_fp_build() + '/osx-build'):
2017-10-21 16:07:08 +02:00
shutil.rmtree(arm.utils.get_fp_build() + '/osx-build', onerror=remove_readonly)
2017-08-21 15:36:21 +02:00
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
def update_gapi_android(self, context):
if os.path.isdir(arm.utils.get_fp_build() + '/android-build'):
2017-10-21 16:07:08 +02:00
shutil.rmtree(arm.utils.get_fp_build() + '/android-build', onerror=remove_readonly)
2017-08-21 15:36:21 +02:00
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
def update_gapi_ios(self, context):
if os.path.isdir(arm.utils.get_fp_build() + '/ios-build'):
2017-10-21 16:07:08 +02:00
shutil.rmtree(arm.utils.get_fp_build() + '/ios-build', onerror=remove_readonly)
2017-08-21 15:36:21 +02:00
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
def update_gapi_html5(self, context):
bpy.data.worlds['Arm'].arm_recompile = True
assets.invalidate_compiled_data(self, context)
class ArmExporterListItem(bpy.types.PropertyGroup):
2018-12-18 23:48:38 +01:00
name: StringProperty(
2017-08-21 15:36:21 +02:00
name="Name",
description="A name for this item",
default="Preset")
2018-12-18 23:48:38 +01:00
arm_project_rp: StringProperty(
2017-08-21 20:16:06 +02:00
name="Render Path",
description="A name for this item",
default="Path")
2018-12-19 13:33:17 +01:00
arm_project_scene: StringProperty(
name="Scene",
description="Scene to load when launching",
default="Scene")
2017-11-09 15:05:58 +01:00
2018-12-18 23:48:38 +01:00
arm_project_target: EnumProperty(
2018-12-05 10:36:36 +01:00
items = [('html5', 'HTML5 (JS)', 'html5'),
('windows-hl', 'Windows (C)', 'windows-hl'),
2018-03-04 19:38:40 +01:00
('krom-windows', 'Windows (Krom)', 'krom-windows'),
2018-12-05 10:36:36 +01:00
('macos-hl', 'macOS (C)', 'macos-hl'),
('krom-macos', 'macOS (Krom)', 'krom-macos'),
('linux-hl', 'Linux (C)', 'linux-hl'),
2018-03-04 19:38:40 +01:00
('krom-linux', 'Linux (Krom)', 'krom-linux'),
2018-12-05 10:36:36 +01:00
('ios-hl', 'iOS (C)', 'ios-hl'),
('android-native-hl', 'Android (C)', 'android-native-hl'),
('node', 'Node (JS)', 'node'),
('custom', 'Custom', 'custom'),],
2018-03-04 19:38:40 +01:00
name="Target", default='html5', description='Build platform')
2017-08-21 15:36:21 +02:00
2018-12-18 23:48:38 +01:00
arm_project_khamake: StringProperty(name="Khamake", description="Specify arguments for the 'node Kha/make' call")
2018-12-05 10:36:36 +01:00
2018-12-18 23:48:38 +01:00
arm_gapi_custom: EnumProperty(
2018-12-05 10:36:36 +01:00
items = [('opengl', 'OpenGL', 'opengl'),
('vulkan', 'Vulkan', 'vulkan'),
('direct3d11', 'Direct3D11', 'direct3d11'),
('direct3d12', 'Direct3D12', 'direct3d12'),
('metal', 'Metal', 'metal')],
name="Graphics API", default='opengl', description='Based on currently selected target', update=update_gapi_custom)
2018-12-18 23:48:38 +01:00
arm_gapi_win: EnumProperty(
2018-12-15 13:33:59 +01:00
items = [('direct3d11', 'Auto', 'direct3d11'),
2017-08-21 15:36:21 +02:00
('opengl', 'OpenGL', 'opengl'),
('vulkan', 'Vulkan', 'vulkan'),
('direct3d11', 'Direct3D11', 'direct3d11'),
('direct3d12', 'Direct3D12', 'direct3d12')],
2018-12-15 13:33:59 +01:00
name="Graphics API", default='direct3d11', description='Based on currently selected target', update=update_gapi_win)
2018-12-18 23:48:38 +01:00
arm_gapi_linux: EnumProperty(
2017-08-21 15:36:21 +02:00
items = [('opengl', 'Auto', 'opengl'),
('opengl', 'OpenGL', 'opengl'),
('vulkan', 'Vulkan', 'vulkan')],
name="Graphics API", default='opengl', description='Based on currently selected target', update=update_gapi_linux)
2018-12-18 23:48:38 +01:00
arm_gapi_android: EnumProperty(
2017-08-21 15:36:21 +02:00
items = [('opengl', 'Auto', 'opengl'),
('opengl', 'OpenGL', 'opengl'),
('vulkan', 'Vulkan', 'vulkan')],
name="Graphics API", default='opengl', description='Based on currently selected target', update=update_gapi_android)
2018-12-18 23:48:38 +01:00
arm_gapi_mac: EnumProperty(
2017-08-21 15:36:21 +02:00
items = [('opengl', 'Auto', 'opengl'),
('opengl', 'OpenGL', 'opengl'),
('metal', 'Metal', 'metal')],
name="Graphics API", default='opengl', description='Based on currently selected target', update=update_gapi_mac)
2018-12-18 23:48:38 +01:00
arm_gapi_ios: EnumProperty(
2017-08-21 15:36:21 +02:00
items = [('opengl', 'Auto', 'opengl'),
('opengl', 'OpenGL', 'opengl'),
('metal', 'Metal', 'metal')],
name="Graphics API", default='opengl', description='Based on currently selected target', update=update_gapi_ios)
2018-12-18 23:48:38 +01:00
arm_gapi_html5: EnumProperty(
2017-08-21 15:36:21 +02:00
items = [('webgl', 'Auto', 'webgl'),
2018-12-05 10:36:36 +01:00
('webgl', 'WebGL2', 'webgl')],
2017-08-21 15:36:21 +02:00
name="Graphics API", default='webgl', description='Based on currently selected target', update=update_gapi_html5)
class ArmExporterList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# We could write some code to decide which icon to use here...
2019-01-13 10:47:06 +01:00
custom_icon = 'DOT'
2017-08-21 15:36:21 +02:00
# Make sure your code supports all 3 layout types
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row()
row.prop(item, "name", text="", emboss=False, icon=custom_icon)
2017-08-22 15:57:49 +02:00
col = row.column()
col.alignment = 'RIGHT'
2018-09-05 10:20:02 +02:00
col.label(text=item.arm_project_target)
2017-08-21 15:36:21 +02:00
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
2018-09-05 10:20:02 +02:00
layout.label(text="", icon = custom_icon)
2017-08-21 15:36:21 +02:00
class ArmExporterListNewItem(bpy.types.Operator):
# Add a new item to the list
bl_idname = "arm_exporterlist.new_item"
bl_label = "Add a new item"
def execute(self, context):
mdata = bpy.data.worlds['Arm']
mdata.arm_exporterlist.add()
mdata.arm_exporterlist_index = len(mdata.arm_exporterlist) - 1
if len(mdata.arm_rplist) > mdata.arm_exporterlist_index:
mdata.arm_exporterlist[-1].arm_project_rp = mdata.arm_rplist[mdata.arm_rplist_index].name
2017-08-21 15:36:21 +02:00
return{'FINISHED'}
class ArmExporterListDeleteItem(bpy.types.Operator):
# Delete the selected item from the list
bl_idname = "arm_exporterlist.delete_item"
bl_label = "Deletes an item"
@classmethod
def poll(self, context):
""" Enable if there's something in the list """
mdata = bpy.data.worlds['Arm']
return len(mdata.arm_exporterlist) > 0
def execute(self, context):
mdata = bpy.data.worlds['Arm']
list = mdata.arm_exporterlist
index = mdata.arm_exporterlist_index
list.remove(index)
if index > 0:
index = index - 1
mdata.arm_exporterlist_index = index
return{'FINISHED'}
2018-11-22 13:31:15 +01:00
class ArmExporterListMoveItem(bpy.types.Operator):
# Move an item in the list
bl_idname = "arm_exporterlist.move_item"
bl_label = "Move an item in the list"
2018-12-18 23:48:38 +01:00
direction: EnumProperty(
2018-11-22 13:31:15 +01:00
items=(
('UP', 'Up', ""),
('DOWN', 'Down', ""),))
def move_index(self):
# Move index of an item render queue while clamping it
mdata = bpy.data.worlds['Arm']
index = mdata.arm_exporterlist_index
list_length = len(mdata.arm_exporterlist) - 1
new_index = 0
if self.direction == 'UP':
new_index = index - 1
elif self.direction == 'DOWN':
new_index = index + 1
new_index = max(0, min(new_index, list_length))
mdata.arm_exporterlist.move(index, new_index)
mdata.arm_exporterlist_index = new_index
def execute(self, context):
mdata = bpy.data.worlds['Arm']
list = mdata.arm_exporterlist
index = mdata.arm_exporterlist_index
if self.direction == 'DOWN':
neighbor = index + 1
self.move_index()
elif self.direction == 'UP':
neighbor = index - 1
self.move_index()
else:
return{'CANCELLED'}
return{'FINISHED'}
2018-03-22 21:43:22 +01:00
class ArmExporterSpecialsMenu(bpy.types.Menu):
bl_label = "More"
bl_idname = "arm_exporterlist_specials"
def draw(self, context):
layout = self.layout
2018-03-24 11:55:10 +01:00
layout.operator("arm.exporter_open_folder")
2018-03-22 21:43:22 +01:00
layout.operator("arm.exporter_gpuprofile")
2018-03-24 11:55:10 +01:00
class ArmoryExporterOpenFolderButton(bpy.types.Operator):
'''Open published folder'''
bl_idname = 'arm.exporter_open_folder'
bl_label = 'Open Folder'
def execute(self, context):
wrd = bpy.data.worlds['Arm']
2018-09-11 08:03:22 +02:00
if len(wrd.arm_exporterlist) == 0:
return {'CANCELLED'}
2018-03-24 11:55:10 +01:00
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
p = os.path.join(arm.utils.get_fp_build(), item.arm_project_target)
if os.path.exists(p):
webbrowser.open('file://' + p)
return{'FINISHED'}
2018-03-22 21:43:22 +01:00
class ArmExporterGpuProfileButton(bpy.types.Operator):
'''GPU profile'''
bl_idname = 'arm.exporter_gpuprofile'
bl_label = 'Open in RenderDoc'
def execute(self, context):
p = arm.utils.get_renderdoc_path()
if p == '':
self.report({'ERROR'}, 'Configure RenderDoc path in Armory add-on preferences')
return {'CANCELLED'}
pbin = ''
base = arm.utils.get_fp_build()
ext1 = '/krom-windows/' + arm.utils.safestr(bpy.data.worlds['Arm'].arm_project_name) + '.exe'
ext2 = '/krom-linux/' + arm.utils.safestr(bpy.data.worlds['Arm'].arm_project_name)
if os.path.exists(base + ext1):
pbin = base + ext1
elif os.path.exists(base + ext2):
pbin = base + ext2
if pbin == '':
self.report({'ERROR'}, 'Publish project using Krom target first')
return {'CANCELLED'}
subprocess.Popen([p, pbin])
return{'FINISHED'}
2017-08-21 15:36:21 +02:00
def register():
bpy.utils.register_class(ArmExporterListItem)
bpy.utils.register_class(ArmExporterList)
bpy.utils.register_class(ArmExporterListNewItem)
bpy.utils.register_class(ArmExporterListDeleteItem)
2018-11-22 13:31:15 +01:00
bpy.utils.register_class(ArmExporterListMoveItem)
2018-03-22 21:43:22 +01:00
bpy.utils.register_class(ArmExporterSpecialsMenu)
bpy.utils.register_class(ArmExporterGpuProfileButton)
2018-03-24 11:55:10 +01:00
bpy.utils.register_class(ArmoryExporterOpenFolderButton)
2017-08-21 15:36:21 +02:00
2018-12-18 23:48:38 +01:00
bpy.types.World.arm_exporterlist = CollectionProperty(type=ArmExporterListItem)
bpy.types.World.arm_exporterlist_index = IntProperty(name="Index for my_list", default=0)
2017-08-21 15:36:21 +02:00
def unregister():
bpy.utils.unregister_class(ArmExporterListItem)
bpy.utils.unregister_class(ArmExporterList)
bpy.utils.unregister_class(ArmExporterListNewItem)
bpy.utils.unregister_class(ArmExporterListDeleteItem)
2018-11-22 13:31:15 +01:00
bpy.utils.unregister_class(ArmExporterListMoveItem)
2018-03-22 21:43:22 +01:00
bpy.utils.unregister_class(ArmExporterSpecialsMenu)
bpy.utils.unregister_class(ArmExporterGpuProfileButton)
2018-03-24 11:55:10 +01:00
bpy.utils.unregister_class(ArmoryExporterOpenFolderButton)