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)
|
|
|
|
|
2017-08-21 15:36:21 +02:00
|
|
|
def update_gapi_win(self, context):
|
|
|
|
if os.path.isdir(arm.utils.get_fp_build() + '/windows-build'):
|
2017-10-21 16:07:08 +02:00
|
|
|
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_winapp(self, context):
|
|
|
|
if os.path.isdir(arm.utils.get_fp_build() + '/windowsapp-build'):
|
2017-10-21 16:07:08 +02:00
|
|
|
shutil.rmtree(arm.utils.get_fp_build() + '/windowsapp-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):
|
|
|
|
name = bpy.props.StringProperty(
|
|
|
|
name="Name",
|
|
|
|
description="A name for this item",
|
|
|
|
default="Preset")
|
|
|
|
|
2017-08-21 20:16:06 +02:00
|
|
|
arm_project_rp = bpy.props.StringProperty(
|
|
|
|
name="Render Path",
|
|
|
|
description="A name for this item",
|
|
|
|
default="Path")
|
|
|
|
|
2017-11-09 15:05:58 +01:00
|
|
|
arm_project_scene = StringProperty(name="Scene", description="Scene to load when launching")
|
|
|
|
|
2017-08-21 15:36:21 +02:00
|
|
|
arm_project_target = EnumProperty(
|
|
|
|
items = [('html5', 'HTML5', 'html5'),
|
2018-03-04 19:38:40 +01:00
|
|
|
('windows', 'Windows (C++)', 'windows'),
|
|
|
|
('krom-windows', 'Windows (Krom)', 'krom-windows'),
|
|
|
|
('windowsapp', 'Windows App', 'windowsapp'),
|
|
|
|
('macos', 'MacOS (C++)', 'macos'),
|
|
|
|
('krom-macos', 'MacOS (Krom)', 'krom-macos'),
|
|
|
|
('linux', 'Linux (C++)', 'linux'),
|
|
|
|
('krom-linux', 'Linux (Krom)', 'krom-linux'),
|
2017-08-21 15:36:21 +02:00
|
|
|
('ios', 'iOS', 'ios'),
|
|
|
|
('android-native', 'Android', 'android-native'),
|
2018-04-06 17:39:22 +02:00
|
|
|
('node', 'Node', 'node'),
|
2018-04-13 19:14:11 +02:00
|
|
|
('windows-hl', 'Windows (HashLink)', 'windows-hl'),
|
|
|
|
('linux-hl', 'Linux (HashLink)', 'linux-hl'),
|
|
|
|
('macos-hl', 'MacOS (HashLink)', 'macos-hl'),],
|
2018-03-04 19:38:40 +01:00
|
|
|
name="Target", default='html5', description='Build platform')
|
2017-08-21 15:36:21 +02:00
|
|
|
|
|
|
|
arm_gapi_win = EnumProperty(
|
|
|
|
items = [('opengl', 'Auto', 'opengl'),
|
|
|
|
('opengl', 'OpenGL', 'opengl'),
|
|
|
|
('vulkan', 'Vulkan', 'vulkan'),
|
|
|
|
('direct3d11', 'Direct3D11', 'direct3d11'),
|
|
|
|
('direct3d12', 'Direct3D12', 'direct3d12')],
|
|
|
|
name="Graphics API", default='opengl', description='Based on currently selected target', update=update_gapi_win)
|
|
|
|
arm_gapi_winapp = EnumProperty(
|
|
|
|
items = [('direct3d11', 'Auto', 'direct3d11'),
|
|
|
|
('direct3d11', 'Direct3D11', 'direct3d11')],
|
|
|
|
name="Graphics API", default='direct3d11', description='Based on currently selected target', update=update_gapi_winapp)
|
|
|
|
arm_gapi_linux = EnumProperty(
|
|
|
|
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)
|
|
|
|
arm_gapi_android = EnumProperty(
|
|
|
|
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)
|
|
|
|
arm_gapi_mac = EnumProperty(
|
|
|
|
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)
|
|
|
|
arm_gapi_ios = EnumProperty(
|
|
|
|
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)
|
|
|
|
arm_gapi_html5 = EnumProperty(
|
|
|
|
items = [('webgl', 'Auto', 'webgl'),
|
|
|
|
('webgl', 'WebGL', 'webgl')],
|
|
|
|
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...
|
|
|
|
custom_icon = 'OBJECT_DATAMODE'
|
|
|
|
|
|
|
|
# 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
|
|
|
|
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-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-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
|
|
|
|
|
|
|
bpy.types.World.arm_exporterlist = bpy.props.CollectionProperty(type=ArmExporterListItem)
|
|
|
|
bpy.types.World.arm_exporterlist_index = bpy.props.IntProperty(name="Index for my_list", default=0)
|
|
|
|
|
|
|
|
def unregister():
|
|
|
|
bpy.utils.unregister_class(ArmExporterListItem)
|
|
|
|
bpy.utils.unregister_class(ArmExporterList)
|
|
|
|
bpy.utils.unregister_class(ArmExporterListNewItem)
|
|
|
|
bpy.utils.unregister_class(ArmExporterListDeleteItem)
|
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)
|