armory/blender/arm/props_ui.py

2332 lines
93 KiB
Python
Raw Normal View History

2018-08-07 08:56:48 +02:00
import os
import time
import bpy
from bpy.props import *
import arm.api
2017-03-15 12:30:14 +01:00
import arm.assets as assets
import arm.log as log
import arm.make as make
import arm.make_state as state
import arm.props as props
import arm.props_properties
import arm.nodes_logic
import arm.proxy
import arm.utils
2016-10-19 13:28:06 +02:00
2020-08-23 23:11:49 +02:00
from arm.lightmapper.utility import icon
from arm.lightmapper.properties.denoiser import oidn, optix
import importlib
2020-08-23 23:11:49 +02:00
2016-10-19 13:28:06 +02:00
# Menu in object region
class ARM_PT_ObjectPropsPanel(bpy.types.Panel):
2016-10-19 13:28:06 +02:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2016-10-19 13:28:06 +02:00
obj = bpy.context.object
if obj == None:
return
2017-10-12 20:21:10 +02:00
2018-12-19 13:33:17 +01:00
layout.prop(obj, 'arm_export')
2017-08-21 12:17:55 +02:00
if not obj.arm_export:
2016-10-19 13:28:06 +02:00
return
2018-12-19 13:33:17 +01:00
layout.prop(obj, 'arm_spawn')
layout.prop(obj, 'arm_mobile')
layout.prop(obj, 'arm_animation_enabled')
2017-08-19 03:08:42 +02:00
if obj.type == 'MESH':
2017-08-19 12:10:06 +02:00
layout.prop(obj, 'arm_instanced')
2017-09-21 18:30:02 +02:00
wrd = bpy.data.worlds['Arm']
2018-09-05 10:20:02 +02:00
layout.prop_search(obj, "arm_tilesheet", wrd, "arm_tilesheetlist", text="Tilesheet")
2017-09-21 18:30:02 +02:00
if obj.arm_tilesheet != '':
selected_ts = None
for ts in wrd.arm_tilesheetlist:
if ts.name == obj.arm_tilesheet:
selected_ts = ts
break
2018-09-05 10:20:02 +02:00
layout.prop_search(obj, "arm_tilesheet_action", selected_ts, "arm_tilesheetactionlist", text="Action")
2017-09-21 18:30:02 +02:00
# Properties list
arm.props_properties.draw_properties(layout, obj)
# Lightmapping props
if obj.type == "MESH":
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_use")
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_resolution")
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if obj.TLM_ObjectProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroup":
pass
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_unwrap_margin")
row = layout.row()
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filter_override")
row = layout.row()
if obj.TLM_ObjectProperties.tlm_mesh_filter_override:
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_mode")
row = layout.row(align=True)
if obj.TLM_ObjectProperties.tlm_mesh_filtering_mode == "Gaussian":
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_gaussian_strength")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
elif obj.TLM_ObjectProperties.tlm_mesh_filtering_mode == "Box":
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_box_strength")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
elif obj.TLM_ObjectProperties.tlm_mesh_filtering_mode == "Bilateral":
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_bilateral_diameter")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_bilateral_color_deviation")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_bilateral_coordinate_deviation")
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
else:
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_median_kernel", expand=True)
row = layout.row(align=True)
row.prop(obj.TLM_ObjectProperties, "tlm_mesh_filtering_iterations")
class ARM_PT_ModifiersPropsPanel(bpy.types.Panel):
2016-10-19 13:28:06 +02:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "modifier"
2018-12-19 13:33:17 +01:00
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2016-10-19 13:28:06 +02:00
obj = bpy.context.object
if obj == None:
return
2016-11-07 00:31:48 +01:00
layout.operator("arm.invalidate_cache")
class ARM_PT_ParticlesPropsPanel(bpy.types.Panel):
2017-09-29 01:18:57 +02:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "particle"
2018-12-19 13:33:17 +01:00
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-09-29 01:18:57 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-09-29 01:18:57 +02:00
obj = bpy.context.particle_system
if obj == None:
return
2017-10-15 18:16:55 +02:00
layout.prop(obj.settings, 'arm_loop')
2017-09-29 17:00:21 +02:00
layout.prop(obj.settings, 'arm_count_mult')
2017-09-29 01:18:57 +02:00
class ARM_PT_PhysicsPropsPanel(bpy.types.Panel):
2017-01-10 10:41:06 +01:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "physics"
2017-10-12 20:21:10 +02:00
2017-01-10 10:41:06 +01:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-01-10 10:41:06 +01:00
obj = bpy.context.object
if obj == None:
return
2017-11-06 13:01:08 +01:00
if obj.rigid_body != None:
layout.prop(obj, 'arm_rb_linear_factor')
layout.prop(obj, 'arm_rb_angular_factor')
layout.prop(obj, 'arm_rb_trigger')
2017-11-06 13:01:08 +01:00
layout.prop(obj, 'arm_rb_force_deactivation')
2018-10-30 12:56:49 +01:00
layout.prop(obj, 'arm_rb_ccd')
2017-11-06 13:01:08 +01:00
if obj.soft_body != None:
layout.prop(obj, 'arm_soft_body_margin')
2017-01-10 10:41:06 +01:00
2016-10-19 13:28:06 +02:00
# Menu in data region
class ARM_PT_DataPropsPanel(bpy.types.Panel):
2016-10-19 13:28:06 +02:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "data"
2018-12-19 13:33:17 +01:00
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2016-10-19 13:28:06 +02:00
obj = bpy.context.object
if obj == None:
return
2017-08-19 03:08:42 +02:00
wrd = bpy.data.worlds['Arm']
2016-10-19 13:28:06 +02:00
if obj.type == 'CAMERA':
2017-08-21 12:17:55 +02:00
layout.prop(obj.data, 'arm_frustum_culling')
2016-11-28 14:40:07 +01:00
elif obj.type == 'MESH' or obj.type == 'FONT' or obj.type == 'META':
2018-12-19 13:33:17 +01:00
layout.prop(obj.data, 'arm_dynamic_usage')
2016-10-19 13:28:06 +02:00
layout.operator("arm.invalidate_cache")
2018-12-19 13:33:17 +01:00
elif obj.type == 'LIGHT':
layout.prop(obj.data, 'arm_clip_start')
layout.prop(obj.data, 'arm_clip_end')
layout.prop(obj.data, 'arm_fov')
layout.prop(obj.data, 'arm_shadows_bias')
layout.prop(wrd, 'arm_light_ies_texture')
layout.prop(wrd, 'arm_light_clouds_texture')
2016-10-19 13:28:06 +02:00
elif obj.type == 'SPEAKER':
layout.prop(obj.data, 'arm_play_on_start')
2017-10-13 15:21:36 +02:00
layout.prop(obj.data, 'arm_loop')
layout.prop(obj.data, 'arm_stream')
2016-10-19 13:28:06 +02:00
elif obj.type == 'ARMATURE':
2020-03-02 15:03:42 +01:00
layout.prop(obj.data, 'arm_autobake')
2018-12-18 16:46:36 +01:00
pass
2016-10-19 13:28:06 +02:00
class ARM_PT_WorldPropsPanel(bpy.types.Panel):
bl_label = "Armory World Properties"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "world"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
world = context.world
if world is None:
return
layout.prop(world, 'arm_use_clouds')
col = layout.column(align=True)
col.enabled = world.arm_use_clouds
col.prop(world, 'arm_clouds_lower')
col.prop(world, 'arm_clouds_upper')
col.prop(world, 'arm_clouds_precipitation')
col.prop(world, 'arm_clouds_secondary')
col.prop(world, 'arm_clouds_wind')
col.prop(world, 'arm_clouds_steps')
class ARM_PT_ScenePropsPanel(bpy.types.Panel):
2016-10-19 13:28:06 +02:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
2018-12-19 13:33:17 +01:00
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2016-10-19 13:28:06 +02:00
scene = bpy.context.scene
if scene == None:
return
2017-08-19 03:08:42 +02:00
row = layout.row()
column = row.column()
2017-11-20 15:59:22 +01:00
row.prop(scene, 'arm_export')
2016-10-19 13:28:06 +02:00
class InvalidateCacheButton(bpy.types.Operator):
'''Delete cached mesh data'''
bl_idname = "arm.invalidate_cache"
bl_label = "Invalidate Cache"
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def execute(self, context):
2017-08-21 12:17:55 +02:00
context.object.data.arm_cached = False
2016-10-19 13:28:06 +02:00
return{'FINISHED'}
2016-12-21 00:51:04 +01:00
class InvalidateMaterialCacheButton(bpy.types.Operator):
'''Delete cached material data'''
bl_idname = "arm.invalidate_material_cache"
bl_label = "Invalidate Cache"
2017-10-12 20:21:10 +02:00
2016-12-21 00:51:04 +01:00
def execute(self, context):
2018-12-19 20:10:34 +01:00
context.material.arm_cached = False
2018-05-24 22:16:28 +02:00
context.material.signature = ''
2016-12-21 00:51:04 +01:00
return{'FINISHED'}
class ARM_PT_MaterialPropsPanel(bpy.types.Panel):
2016-10-19 13:28:06 +02:00
bl_label = "Armory Props"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2016-10-19 13:28:06 +02:00
mat = bpy.context.material
if mat == None:
return
2018-12-19 13:33:17 +01:00
layout.prop(mat, 'arm_cast_shadow')
columnb = layout.column()
2018-08-08 22:43:14 +02:00
wrd = bpy.data.worlds['Arm']
columnb.enabled = len(wrd.arm_rplist) > 0 and arm.utils.get_rp().rp_renderer == 'Forward'
columnb.prop(mat, 'arm_receive_shadow')
2018-12-19 13:33:17 +01:00
layout.prop(mat, 'arm_two_sided')
columnb = layout.column()
2017-08-21 12:17:55 +02:00
columnb.enabled = not mat.arm_two_sided
columnb.prop(mat, 'arm_cull_mode')
2018-12-19 13:33:17 +01:00
layout.prop(mat, 'arm_material_id')
layout.prop(mat, 'arm_overlay')
layout.prop(mat, 'arm_decal')
layout.prop(mat, 'arm_discard')
columnb = layout.column()
2017-08-21 12:17:55 +02:00
columnb.enabled = mat.arm_discard
columnb.prop(mat, 'arm_discard_opacity')
columnb.prop(mat, 'arm_discard_opacity_shadows')
2018-12-19 13:33:17 +01:00
layout.prop(mat, 'arm_custom_material')
layout.prop(mat, 'arm_skip_context')
layout.prop(mat, 'arm_particle_fade')
layout.prop(mat, 'arm_billboard')
layout.operator("arm.invalidate_material_cache")
class ARM_PT_MaterialBlendingPropsPanel(bpy.types.Panel):
bl_label = "Blending"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_MaterialPropsPanel"
def draw_header(self, context):
2019-04-02 18:53:53 +02:00
if context.material == None:
return
self.layout.prop(context.material, 'arm_blending', text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
mat = bpy.context.material
if mat == None:
return
flow = layout.grid_flow()
flow.enabled = mat.arm_blending
col = flow.column()
2018-08-08 22:43:14 +02:00
col.prop(mat, 'arm_blending_source')
col.prop(mat, 'arm_blending_destination')
col.prop(mat, 'arm_blending_operation')
col = flow.column()
2018-08-08 22:43:14 +02:00
col.prop(mat, 'arm_blending_source_alpha')
col.prop(mat, 'arm_blending_destination_alpha')
col.prop(mat, 'arm_blending_operation_alpha')
2017-09-17 16:59:00 +02:00
class ARM_PT_ArmoryPlayerPanel(bpy.types.Panel):
2017-01-17 18:13:54 +01:00
bl_label = "Armory Player"
2016-10-19 13:28:06 +02:00
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2016-10-19 13:28:06 +02:00
wrd = bpy.data.worlds['Arm']
2017-01-17 18:13:54 +01:00
row = layout.row(align=True)
row.alignment = 'EXPAND'
if state.proc_play is None and state.proc_build is None:
2017-02-23 13:30:11 +01:00
row.operator("arm.play", icon="PLAY")
else:
row.operator("arm.stop", icon="MESH_PLANE")
2017-01-17 18:13:54 +01:00
row.operator("arm.clean_menu")
2018-11-13 14:17:47 +01:00
layout.prop(wrd, 'arm_runtime')
2018-06-19 23:21:53 +02:00
layout.prop(wrd, 'arm_play_camera')
2020-05-23 12:18:07 +02:00
layout.prop(wrd, 'arm_play_scene')
2016-10-19 13:28:06 +02:00
if log.num_warnings > 0:
box = layout.box()
# Less spacing between lines
col = box.column(align=True)
col.label(text=f'{log.num_warnings} warnings occurred during compilation!', icon='ERROR')
# Blank icon to achieve the same indentation as the line before
col.label(text='Please open the console to get more information.', icon='BLANK1')
class ARM_PT_ArmoryExporterPanel(bpy.types.Panel):
2017-08-19 03:08:42 +02:00
bl_label = "Armory Exporter"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-08-19 03:08:42 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-08-19 03:08:42 +02:00
wrd = bpy.data.worlds['Arm']
2017-01-23 20:41:45 +01:00
row = layout.row(align=True)
row.alignment = 'EXPAND'
row.operator("arm.build_project")
2018-05-24 22:16:28 +02:00
# row.operator("arm.patch_project")
2018-03-15 23:24:48 +01:00
row.operator("arm.publish_project", icon="EXPORT")
2017-08-21 15:36:21 +02:00
row.enabled = wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0
rows = 2
if len(wrd.arm_exporterlist) > 1:
rows = 4
row = layout.row()
2019-03-30 07:48:55 +01:00
row.template_list("ARM_UL_ExporterList", "The_List", wrd, "arm_exporterlist", wrd, "arm_exporterlist_index", rows=rows)
2017-08-21 15:36:21 +02:00
col = row.column(align=True)
2018-12-18 23:48:38 +01:00
col.operator("arm_exporterlist.new_item", icon='ADD', text="")
col.operator("arm_exporterlist.delete_item", icon='REMOVE', text="")
2019-03-30 07:48:55 +01:00
col.menu("ARM_MT_ExporterListSpecials", icon='DOWNARROW_HLT', text="")
2017-08-21 15:36:21 +02:00
2018-11-22 13:31:15 +01:00
if len(wrd.arm_exporterlist) > 1:
col.separator()
op = col.operator("arm_exporterlist.move_item", icon='TRIA_UP', text="")
op.direction = 'UP'
op = col.operator("arm_exporterlist.move_item", icon='TRIA_DOWN', text="")
op.direction = 'DOWN'
2017-08-21 15:36:21 +02:00
if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0:
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
2018-03-15 23:24:48 +01:00
box = layout.box().column()
box.prop(item, 'arm_project_target')
2018-12-05 10:36:36 +01:00
if item.arm_project_target == 'custom':
box.prop(item, 'arm_project_khamake')
2018-03-15 23:24:48 +01:00
box.prop(item, arm.utils.target_to_gapi(item.arm_project_target))
2017-08-21 20:16:06 +02:00
wrd.arm_rpcache_list.clear() # Make UIList work with prop_search()
for i in wrd.arm_rplist:
wrd.arm_rpcache_list.add().name = i.name
2018-09-05 10:20:02 +02:00
box.prop_search(item, "arm_project_rp", wrd, "arm_rpcache_list", text="Render Path")
box.prop_search(item, 'arm_project_scene', bpy.data, 'scenes', text='Scene')
2018-01-23 19:42:06 +01:00
layout.separator()
2018-03-15 23:24:48 +01:00
col = layout.column()
col.prop(wrd, 'arm_project_name')
col.prop(wrd, 'arm_project_package')
2018-06-13 14:00:01 +02:00
col.prop(wrd, 'arm_project_bundle')
Add Android Settings + LN Set Vibrate 1. For the new settings to fully function, you need to update the submodules so that this Pull Request (https://github.com/Kode/kincmake/pull/100) gets into armsdk. Extended settings via khafile.js. 2. Added Android Settings panel: - invisible until the target platform android-hl is added to the list; - inactive until the target platform android-hl is selected in the list. Options: - Orientation; - Compile Version SDK - from 26 to 30, default 29; - Minimal Version SDK - from 14 to 30, default 14; - Target Version SDK - from 26 to 30, default 29; - Permissions - a list of permissions. If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty; - Android ABI Filters - a list of platforms to build for (arm64-v8a, armeabi-v7a, x86, x86_64). If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty. If the list is empty, then all platforms will be used (as before). 3. The enum (names of permissions) and the function have been added to the utils.py modules, which adds the specified value to the list of permissions. Feature added for ease of use from different locations (different logical nodes). 4. List of permissions: - ACCESS_COARSE_LOCATION - Allows an app to access approximate location; - ACCESS_NETWORK_STATE - Allows applications to access information about networks; - ACCESS_FINE_LOCATION - Allows an app to access precise location; - ACCESS_WIFI_STATE - Allows applications to access information about Wi-Fi network; - BLUETOOTH - Allows applications to connect to paired bluetooth devices; - BLUETOOTH_ADMIN - Allows applications to discover and pair bluetooth devices; - CAMERA - Required to be able to access the camera device; - EXPAND_STATUS_BAR - Allows an application to expand or collapse the status bar; - FOREGROUND_SERVICE - Allows a regular application to use Service.startForeground; - GET_ACCOUNTS - Allows access to the list of accounts in the Accounts Service; - INTERNET - Allows applications to open network sockets'; - READ_EXTERNAL_STORAGE - Allows an application to read from external storage; - VIBRATE - Allows access to the vibrator; - WRITE_EXTERNAL_STORAGE - Allows an application to write to external storage. 5. Added logical node Set Vibrate: Category: Native Pulses the vibration hardware on the device for time in milliseconds, if such hardware exists. Input parameters: - Milliseconds - time in milliseconds (data type Int, default value 100). When adding the logical node Set Vibrate, the permission is automatically added to the list, even if the target android-hl has not been added to the export list (using a function from utils.py).
2020-10-17 15:47:54 +02:00
col.prop(wrd, 'arm_project_version')
2018-06-13 14:00:01 +02:00
col.prop(wrd, 'arm_project_icon')
2018-12-15 19:03:11 +01:00
col.prop(wrd, 'arm_dce')
col.prop(wrd, 'arm_compiler_inline')
col.prop(wrd, 'arm_minify_js')
col.prop(wrd, 'arm_optimize_data')
2018-12-18 16:46:36 +01:00
col.prop(wrd, 'arm_asset_compression')
2019-05-14 11:43:41 +02:00
col.prop(wrd, 'arm_single_data_file')
2017-08-19 03:08:42 +02:00
Add Android Settings + LN Set Vibrate 1. For the new settings to fully function, you need to update the submodules so that this Pull Request (https://github.com/Kode/kincmake/pull/100) gets into armsdk. Extended settings via khafile.js. 2. Added Android Settings panel: - invisible until the target platform android-hl is added to the list; - inactive until the target platform android-hl is selected in the list. Options: - Orientation; - Compile Version SDK - from 26 to 30, default 29; - Minimal Version SDK - from 14 to 30, default 14; - Target Version SDK - from 26 to 30, default 29; - Permissions - a list of permissions. If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty; - Android ABI Filters - a list of platforms to build for (arm64-v8a, armeabi-v7a, x86, x86_64). If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty. If the list is empty, then all platforms will be used (as before). 3. The enum (names of permissions) and the function have been added to the utils.py modules, which adds the specified value to the list of permissions. Feature added for ease of use from different locations (different logical nodes). 4. List of permissions: - ACCESS_COARSE_LOCATION - Allows an app to access approximate location; - ACCESS_NETWORK_STATE - Allows applications to access information about networks; - ACCESS_FINE_LOCATION - Allows an app to access precise location; - ACCESS_WIFI_STATE - Allows applications to access information about Wi-Fi network; - BLUETOOTH - Allows applications to connect to paired bluetooth devices; - BLUETOOTH_ADMIN - Allows applications to discover and pair bluetooth devices; - CAMERA - Required to be able to access the camera device; - EXPAND_STATUS_BAR - Allows an application to expand or collapse the status bar; - FOREGROUND_SERVICE - Allows a regular application to use Service.startForeground; - GET_ACCOUNTS - Allows access to the list of accounts in the Accounts Service; - INTERNET - Allows applications to open network sockets'; - READ_EXTERNAL_STORAGE - Allows an application to read from external storage; - VIBRATE - Allows access to the vibrator; - WRITE_EXTERNAL_STORAGE - Allows an application to write to external storage. 5. Added logical node Set Vibrate: Category: Native Pulses the vibration hardware on the device for time in milliseconds, if such hardware exists. Input parameters: - Milliseconds - time in milliseconds (data type Int, default value 100). When adding the logical node Set Vibrate, the permission is automatically added to the list, even if the target android-hl has not been added to the export list (using a function from utils.py).
2020-10-17 15:47:54 +02:00
class ARM_PT_ArmoryExporterAndroidSettingsPanel(bpy.types.Panel):
bl_label = "Android Settings"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = { 'DEFAULT_CLOSED' }
bl_parent_id = "ARM_PT_ArmoryExporterPanel"
@classmethod
def poll(cls, context):
wrd = bpy.data.worlds['Arm']
is_check = False
for item in wrd.arm_exporterlist:
is_check = item.arm_project_target == 'android-hl'
if is_check:
break
return is_check
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0:
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
layout.enabled = item.arm_project_target == 'android-hl'
# Options
row = layout.row()
row.prop(wrd, 'arm_winorient')
row = layout.row()
row.prop(wrd, 'arm_project_android_sdk_compile')
row = layout.row()
row.prop(wrd, 'arm_project_android_sdk_min')
row = layout.row()
row.prop(wrd, 'arm_project_android_sdk_target')
class ARM_PT_ArmoryExporterAndroidPermissionsPanel(bpy.types.Panel):
bl_label = "Permissions"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = { 'DEFAULT_CLOSED' }
bl_parent_id = "ARM_PT_ArmoryExporterAndroidSettingsPanel"
@classmethod
def poll(cls, context):
wrd = bpy.data.worlds['Arm']
is_check = False
for item in wrd.arm_exporterlist:
is_check = item.arm_project_target == 'android-hl'
if is_check:
break
return is_check
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0:
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
layout.enabled = item.arm_project_target == 'android-hl'
# Permission
row = layout.row()
rows = 2
if len(wrd.arm_exporter_android_permission_list) > 1:
rows = 4
row.template_list("ARM_UL_Exporter_AndroidPermissionList", "The_List", wrd, "arm_exporter_android_permission_list", wrd, "arm_exporter_android_permission_list_index", rows=rows)
col = row.column(align=True)
col.operator("arm_exporter_android_permission_list.new_item", icon='ADD', text="")
col.operator("arm_exporter_android_permission_list.delete_item", icon='REMOVE', text="")
row = layout.row()
if wrd.arm_exporter_android_permission_list_index >= 0 and len(wrd.arm_exporter_android_permission_list) > 0:
item = wrd.arm_exporter_android_permission_list[wrd.arm_exporter_android_permission_list_index]
row = layout.row()
row.prop(item, 'arm_android_permissions')
class ARM_PT_ArmoryExporterAndroidAbiPanel(bpy.types.Panel):
bl_label = "Android ABI Filters"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = { 'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_ArmoryExporterAndroidSettingsPanel"
@classmethod
def poll(cls, context):
wrd = bpy.data.worlds['Arm']
is_check = False
for item in wrd.arm_exporterlist:
is_check = item.arm_project_target == 'android-hl'
if is_check:
break
return is_check
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0:
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
layout.enabled = item.arm_project_target == 'android-hl'
# ABIs
row = layout.row()
rows = 2
if len(wrd.arm_exporter_android_abi_list) > 1:
rows = 4
row.template_list("ARM_UL_Exporter_AndroidAbiList", "The_List", wrd, "arm_exporter_android_abi_list", wrd, "arm_exporter_android_abi_list_index", rows=rows)
col = row.column(align=True)
col.operator("arm_exporter_android_abi_list.new_item", icon='ADD', text="")
col.operator("arm_exporter_android_abi_list.delete_item", icon='REMOVE', text="")
row = layout.row()
if wrd.arm_exporter_android_abi_list_index >= 0 and len(wrd.arm_exporter_android_abi_list) > 0:
item = wrd.arm_exporter_android_abi_list[wrd.arm_exporter_android_abi_list_index]
row = layout.row()
row.prop(item, 'arm_android_abi')
class ARM_PT_ArmoryExporterAndroidBuildAPKPanel(bpy.types.Panel):
bl_label = "Building APK"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = { 'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_ArmoryExporterAndroidSettingsPanel"
@classmethod
def poll(cls, context):
wrd = bpy.data.worlds['Arm']
is_check = False
for item in wrd.arm_exporterlist:
is_check = item.arm_project_target == 'android-hl'
if is_check:
break
return is_check
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0:
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
layout.enabled = item.arm_project_target == 'android-hl'
row = layout.row()
row.prop(wrd, 'arm_project_android_build_apk')
path = arm.utils.get_android_sdk_root_path()
row.enabled = len(path) > 0
row = layout.row()
row.prop(wrd, 'arm_project_android_list_avd')
col = row.column(align=True)
col.operator('arm.update_list_android_emulator', text='', icon='FILE_REFRESH')
col.enabled = len(path) > 0
col = row.column(align=True)
col.operator('arm.run_android_emulator', text='', icon='PLAY')
col.enabled = len(path) > 0 and len(arm.utils.get_android_emulator_name()) > 0
row = layout.row()
row.prop(wrd, 'arm_project_android_run_avd')
row.enabled = arm.utils.get_project_android_build_apk() and len(arm.utils.get_android_emulator_name()) > 0
class ARM_PT_ArmoryProjectPanel(bpy.types.Panel):
2017-08-19 03:08:42 +02:00
bl_label = "Armory Project"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-08-19 03:08:42 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-08-10 14:10:37 +02:00
row = layout.row(align=True)
2020-04-12 20:04:28 +02:00
row.operator("arm.open_editor", icon="DESKTOP")
2018-03-15 23:24:48 +01:00
row.operator("arm.open_project_folder", icon="FILE_FOLDER")
2017-08-19 03:08:42 +02:00
class ARM_PT_ProjectFlagsPanel(bpy.types.Panel):
2018-12-24 16:26:43 +01:00
bl_label = "Flags"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_parent_id = "ARM_PT_ArmoryProjectPanel"
2018-12-24 16:26:43 +01:00
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
layout.prop(wrd, 'arm_verbose_output')
2019-02-10 11:47:42 +01:00
layout.prop(wrd, 'arm_cache_build')
layout.prop(wrd, 'arm_live_patch')
2018-12-19 13:33:17 +01:00
layout.prop(wrd, 'arm_stream_scene')
layout.prop(wrd, 'arm_batch_meshes')
layout.prop(wrd, 'arm_batch_materials')
layout.prop(wrd, 'arm_write_config')
layout.prop(wrd, 'arm_minimize')
layout.prop(wrd, 'arm_deinterleaved_buffers')
layout.prop(wrd, 'arm_export_tangents')
layout.prop(wrd, 'arm_loadscreen')
layout.prop(wrd, 'arm_texture_quality')
layout.prop(wrd, 'arm_sound_quality')
2017-08-19 03:08:42 +02:00
class ARM_PT_ProjectFlagsDebugConsolePanel(bpy.types.Panel):
bl_label = "Debug Console"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_ProjectFlagsPanel"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
row = layout.row()
row.enabled = wrd.arm_ui != 'Disabled'
row.prop(wrd, 'arm_debug_console')
row = layout.row()
row.enabled = wrd.arm_debug_console
row.prop(wrd, 'arm_debug_console_position')
row = layout.row()
row.enabled = wrd.arm_debug_console
row.prop(wrd, 'arm_debug_console_scale')
row = layout.row()
row.enabled = wrd.arm_debug_console
row.prop(wrd, 'arm_debug_console_visible')
class ARM_PT_ProjectWindowPanel(bpy.types.Panel):
2018-12-24 16:26:43 +01:00
bl_label = "Window"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_ArmoryProjectPanel"
2018-12-24 16:26:43 +01:00
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
2018-12-19 13:33:17 +01:00
layout.prop(wrd, 'arm_winmode')
layout.prop(wrd, 'arm_winresize')
col = layout.column()
col.enabled = wrd.arm_winresize
col.prop(wrd, 'arm_winmaximize')
layout.prop(wrd, 'arm_winminimize')
layout.prop(wrd, 'arm_vsync')
2017-08-19 03:08:42 +02:00
class ARM_PT_ProjectModulesPanel(bpy.types.Panel):
2018-12-24 16:26:43 +01:00
bl_label = "Modules"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_ArmoryProjectPanel"
2018-12-24 16:26:43 +01:00
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
2018-12-19 13:33:17 +01:00
layout.prop(wrd, 'arm_audio')
layout.prop(wrd, 'arm_physics')
if wrd.arm_physics != 'Disabled':
2018-12-19 13:33:17 +01:00
layout.prop(wrd, 'arm_physics_engine')
layout.prop(wrd, 'arm_navigation')
if wrd.arm_navigation != 'Disabled':
2018-12-19 13:33:17 +01:00
layout.prop(wrd, 'arm_navigation_engine')
layout.prop(wrd, 'arm_ui')
layout.prop_search(wrd, 'arm_khafile', bpy.data, 'texts', text='Khafile')
layout.prop(wrd, 'arm_project_root')
2016-10-19 13:28:06 +02:00
2017-08-19 03:08:42 +02:00
class ArmVirtualInputPanel(bpy.types.Panel):
bl_label = "Armory Virtual Input"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-08-19 03:08:42 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-08-19 03:08:42 +02:00
2016-10-19 13:28:06 +02:00
class ArmoryPlayButton(bpy.types.Operator):
'''Launch player in new window'''
bl_idname = 'arm.play'
bl_label = 'Play'
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def execute(self, context):
2018-06-19 23:21:53 +02:00
if state.proc_build != None:
2017-01-10 15:06:46 +01:00
return {"CANCELLED"}
2017-10-12 20:21:10 +02:00
2017-03-15 12:30:14 +01:00
if not arm.utils.check_saved(self):
return {"CANCELLED"}
2017-03-15 12:30:14 +01:00
if not arm.utils.check_sdkpath(self):
2017-01-08 00:56:49 +01:00
return {"CANCELLED"}
2017-07-27 10:23:59 +02:00
2019-01-21 16:57:38 +01:00
arm.utils.check_projectpath(None)
2018-08-15 15:42:25 +02:00
arm.utils.check_default_props()
2016-12-09 02:08:01 +01:00
2016-10-19 13:28:06 +02:00
assets.invalidate_enabled = False
2019-02-10 11:47:42 +01:00
make.play()
2016-10-19 13:28:06 +02:00
assets.invalidate_enabled = True
return{'FINISHED'}
class ArmoryStopButton(bpy.types.Operator):
'''Stop currently running player'''
bl_idname = 'arm.stop'
bl_label = 'Stop'
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def execute(self, context):
2018-06-19 23:21:53 +02:00
if state.proc_play != None:
state.proc_play.terminate()
state.proc_play = None
elif state.proc_build != None:
state.proc_build.terminate()
state.proc_build = None
2016-10-19 13:28:06 +02:00
return{'FINISHED'}
2017-01-23 20:41:45 +01:00
class ArmoryBuildProjectButton(bpy.types.Operator):
'''Build and compile project'''
bl_idname = 'arm.build_project'
bl_label = 'Build'
2017-10-12 20:21:10 +02:00
2017-01-23 20:41:45 +01:00
def execute(self, context):
2017-03-15 12:30:14 +01:00
if not arm.utils.check_saved(self):
2017-01-23 20:41:45 +01:00
return {"CANCELLED"}
2017-03-15 12:30:14 +01:00
if not arm.utils.check_sdkpath(self):
2017-01-23 20:41:45 +01:00
return {"CANCELLED"}
2017-09-08 14:07:41 +02:00
arm.utils.check_projectpath(self)
2018-08-15 15:42:25 +02:00
arm.utils.check_default_props()
2017-08-21 20:16:06 +02:00
2017-08-21 15:36:21 +02:00
wrd = bpy.data.worlds['Arm']
2017-08-21 20:16:06 +02:00
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
if item.arm_project_rp == '':
item.arm_project_rp = wrd.arm_rplist[wrd.arm_rplist_index].name
2019-01-24 15:09:49 +01:00
if item.arm_project_scene == None:
item.arm_project_scene = context.scene
2017-08-21 20:16:06 +02:00
# Assume unique rp names
rplist_index = wrd.arm_rplist_index
for i in range(0, len(wrd.arm_rplist)):
if wrd.arm_rplist[i].name == item.arm_project_rp:
wrd.arm_rplist_index = i
break
2017-08-21 15:36:21 +02:00
assets.invalidate_shader_cache(None, None)
2017-01-23 20:41:45 +01:00
assets.invalidate_enabled = False
2018-06-19 23:21:53 +02:00
make.build(item.arm_project_target, is_export=True)
make.compile()
2017-10-12 20:21:10 +02:00
wrd.arm_rplist_index = rplist_index
assets.invalidate_enabled = True
return{'FINISHED'}
2017-09-04 12:14:14 +02:00
class ArmoryPublishProjectButton(bpy.types.Operator):
'''Build project ready for publishing'''
bl_idname = 'arm.publish_project'
bl_label = 'Publish'
2017-10-12 20:21:10 +02:00
2017-09-04 12:14:14 +02:00
def execute(self, context):
if not arm.utils.check_saved(self):
return {"CANCELLED"}
if not arm.utils.check_sdkpath(self):
return {"CANCELLED"}
2017-09-08 14:07:41 +02:00
self.report({'INFO'}, 'Publishing project, check console for details.')
arm.utils.check_projectpath(self)
2018-08-15 15:42:25 +02:00
arm.utils.check_default_props()
2017-09-04 12:14:14 +02:00
wrd = bpy.data.worlds['Arm']
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
if item.arm_project_rp == '':
item.arm_project_rp = wrd.arm_rplist[wrd.arm_rplist_index].name
2019-01-25 08:07:35 +01:00
if item.arm_project_scene == None:
item.arm_project_scene = context.scene
2017-09-04 12:14:14 +02:00
# Assume unique rp names
rplist_index = wrd.arm_rplist_index
for i in range(0, len(wrd.arm_rplist)):
if wrd.arm_rplist[i].name == item.arm_project_rp:
wrd.arm_rplist_index = i
break
2018-05-24 22:16:28 +02:00
make.clean()
2017-09-04 12:14:14 +02:00
assets.invalidate_enabled = False
2018-06-19 23:21:53 +02:00
make.build(item.arm_project_target, is_publish=True, is_export=True)
make.compile()
2017-08-21 20:16:06 +02:00
wrd.arm_rplist_index = rplist_index
2017-09-04 12:14:14 +02:00
assets.invalidate_enabled = True
2017-01-23 20:41:45 +01:00
return{'FINISHED'}
2017-02-28 13:48:19 +01:00
class ArmoryOpenProjectFolderButton(bpy.types.Operator):
2016-10-19 13:28:06 +02:00
'''Open project folder'''
2017-02-28 13:48:19 +01:00
bl_idname = 'arm.open_project_folder'
2016-10-19 13:28:06 +02:00
bl_label = 'Project Folder'
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def execute(self, context):
2017-03-15 12:30:14 +01:00
if not arm.utils.check_saved(self):
2016-10-31 19:29:03 +01:00
return {"CANCELLED"}
arm.utils.open_folder(arm.utils.get_fp())
2016-10-19 13:28:06 +02:00
return{'FINISHED'}
class ArmoryOpenEditorButton(bpy.types.Operator):
'''Launch this project in the IDE'''
bl_idname = 'arm.open_editor'
2019-05-07 09:54:10 +02:00
bl_label = 'Code Editor'
bl_description = 'Open Project in IDE'
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def execute(self, context):
2017-03-15 12:30:14 +01:00
if not arm.utils.check_saved(self):
2016-10-31 19:29:03 +01:00
return {"CANCELLED"}
2018-09-27 12:38:54 +02:00
arm.utils.check_default_props()
2018-09-21 21:32:45 +02:00
if not os.path.exists(arm.utils.get_fp() + "/khafile.js"):
print('Generating Krom project for IDE build configuration')
2018-09-21 21:32:45 +02:00
make.build('krom')
2018-08-07 08:56:48 +02:00
arm.utils.open_editor()
2016-10-19 13:28:06 +02:00
return{'FINISHED'}
2016-12-01 18:46:48 +01:00
class CleanMenu(bpy.types.Menu):
bl_label = "Ok?"
bl_idname = "OBJECT_MT_clean_menu"
def draw(self, context):
layout = self.layout
layout.operator("arm.clean_project")
class CleanButtonMenu(bpy.types.Operator):
'''Clean cached data'''
bl_label = "Clean"
bl_idname = "arm.clean_menu"
2017-10-12 20:21:10 +02:00
2016-12-01 18:46:48 +01:00
def execute(self, context):
bpy.ops.wm.call_menu(name=CleanMenu.bl_idname)
return {"FINISHED"}
2016-11-05 14:12:36 +01:00
class ArmoryCleanProjectButton(bpy.types.Operator):
'''Delete all cached project data'''
bl_idname = 'arm.clean_project'
bl_label = 'Clean Project'
2017-10-12 20:21:10 +02:00
2016-10-19 13:28:06 +02:00
def execute(self, context):
2017-03-15 12:30:14 +01:00
if not arm.utils.check_saved(self):
2016-10-31 19:29:03 +01:00
return {"CANCELLED"}
2018-05-24 22:16:28 +02:00
make.clean()
2016-10-19 13:28:06 +02:00
return{'FINISHED'}
def draw_view3d_header(self, context):
if state.proc_build is not None:
2018-09-05 10:20:02 +02:00
self.layout.label(text='Compiling..')
2018-05-24 22:16:28 +02:00
elif log.info_text != '':
2018-09-05 10:20:02 +02:00
self.layout.label(text=log.info_text)
2016-10-19 13:28:06 +02:00
2020-08-10 14:42:42 +02:00
def draw_view3d_object_menu(self, context):
self.layout.separator()
self.layout.operator_context = 'INVOKE_DEFAULT'
self.layout.operator('arm.copy_traits_to_active')
class ARM_PT_RenderPathPanel(bpy.types.Panel):
2017-08-19 12:10:06 +02:00
bl_label = "Armory Render Path"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
2017-08-21 20:16:06 +02:00
2017-08-19 12:10:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-08-19 12:10:06 +02:00
wrd = bpy.data.worlds['Arm']
2017-08-21 20:16:06 +02:00
rows = 2
if len(wrd.arm_rplist) > 1:
rows = 4
2017-08-21 12:17:55 +02:00
row = layout.row()
2019-03-30 07:48:55 +01:00
row.template_list("ARM_UL_RPList", "The_List", wrd, "arm_rplist", wrd, "arm_rplist_index", rows=rows)
2017-08-21 20:16:06 +02:00
col = row.column(align=True)
2018-12-18 23:48:38 +01:00
col.operator("arm_rplist.new_item", icon='ADD', text="")
col.operator("arm_rplist.delete_item", icon='REMOVE', text="")
2017-08-21 20:16:06 +02:00
2018-11-22 13:31:15 +01:00
if len(wrd.arm_rplist) > 1:
col.separator()
op = col.operator("arm_rplist.move_item", icon='TRIA_UP', text="")
op.direction = 'UP'
op = col.operator("arm_rplist.move_item", icon='TRIA_DOWN', text="")
op.direction = 'DOWN'
2018-03-15 16:02:56 +01:00
if wrd.arm_rplist_index < 0 or len(wrd.arm_rplist) == 0:
return
2017-08-21 20:16:06 +02:00
2018-03-15 16:02:56 +01:00
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
if len(arm.api.drivers) > 0:
rpdat.rp_driver_list.clear()
rpdat.rp_driver_list.add().name = 'Armory'
for d in arm.api.drivers:
rpdat.rp_driver_list.add().name = arm.api.drivers[d]['driver_name']
2018-09-05 10:20:02 +02:00
layout.prop_search(rpdat, "rp_driver", rpdat, "rp_driver_list", text="Driver")
2017-08-23 23:37:55 +02:00
layout.separator()
2018-03-15 16:02:56 +01:00
if rpdat.rp_driver != 'Armory' and arm.api.drivers[rpdat.rp_driver]['draw_props'] != None:
arm.api.drivers[rpdat.rp_driver]['draw_props'](layout)
return
2018-11-15 14:07:03 +01:00
class ARM_PT_RenderPathRendererPanel(bpy.types.Panel):
2018-12-19 13:33:17 +01:00
bl_label = "Renderer"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_RenderPathPanel"
2018-12-19 13:33:17 +01:00
def draw(self, context):
layout = self.layout
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-12-19 13:33:17 +01:00
wrd = bpy.data.worlds['Arm']
2019-01-09 21:25:09 +01:00
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
2018-12-19 13:33:17 +01:00
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
layout.prop(rpdat, 'rp_renderer')
2018-12-10 09:46:46 +01:00
if rpdat.rp_renderer == 'Forward':
2018-12-19 13:33:17 +01:00
layout.prop(rpdat, 'rp_depthprepass')
layout.prop(rpdat, 'arm_material_model')
layout.prop(rpdat, 'rp_translucency_state')
layout.prop(rpdat, 'rp_overlays_state')
layout.prop(rpdat, 'rp_decals_state')
layout.prop(rpdat, 'rp_blending_state')
layout.prop(rpdat, 'rp_draw_order')
layout.prop(rpdat, 'arm_samples_per_pixel')
layout.prop(rpdat, 'arm_texture_filter')
layout.prop(rpdat, 'rp_sss_state')
col = layout.column()
col.enabled = rpdat.rp_sss_state != 'Off'
col.prop(rpdat, 'arm_sss_width')
layout.prop(rpdat, 'arm_rp_displacement')
2018-05-07 23:09:38 +02:00
if rpdat.arm_rp_displacement == 'Tessellation':
2018-12-19 13:33:17 +01:00
layout.label(text='Mesh')
layout.prop(rpdat, 'arm_tess_mesh_inner')
layout.prop(rpdat, 'arm_tess_mesh_outer')
layout.label(text='Shadow')
layout.prop(rpdat, 'arm_tess_shadows_inner')
layout.prop(rpdat, 'arm_tess_shadows_outer')
2018-12-19 13:33:17 +01:00
layout.prop(rpdat, 'arm_particles')
layout.prop(rpdat, 'arm_skin')
row = layout.row()
2019-04-06 14:13:38 +02:00
row.enabled = rpdat.arm_skin == 'On'
2018-12-19 13:33:17 +01:00
row.prop(rpdat, 'arm_skin_max_bones_auto')
row = layout.row()
row.enabled = not rpdat.arm_skin_max_bones_auto
row.prop(rpdat, 'arm_skin_max_bones')
layout.prop(rpdat, "rp_hdr")
layout.prop(rpdat, "rp_stereo")
layout.prop(rpdat, 'arm_culling')
layout.prop(rpdat, 'rp_pp')
2018-12-19 13:33:17 +01:00
class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
2018-12-19 13:33:17 +01:00
bl_label = "Shadows"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_RenderPathPanel"
2017-08-21 20:16:06 +02:00
2018-12-19 13:33:17 +01:00
def draw_header(self, context):
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
self.layout.prop(rpdat, "rp_shadows", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-12-19 13:33:17 +01:00
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
layout.enabled = rpdat.rp_shadows
layout.prop(rpdat, 'rp_shadowmap_cube')
layout.prop(rpdat, 'rp_shadowmap_cascade')
layout.prop(rpdat, 'rp_shadowmap_cascades')
col = layout.column()
col2 = col.column()
col2.enabled = rpdat.rp_shadowmap_cascades != '1'
col2.prop(rpdat, 'arm_shadowmap_split')
col.prop(rpdat, 'arm_shadowmap_bounds')
col.prop(rpdat, 'arm_pcfsize')
class ARM_PT_RenderPathVoxelsPanel(bpy.types.Panel):
bl_label = "Voxel AO"
2018-12-19 13:33:17 +01:00
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_RenderPathPanel"
2018-12-19 13:33:17 +01:00
def draw_header(self, context):
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
self.layout.prop(rpdat, "rp_voxelao", text="")
2018-12-19 13:33:17 +01:00
def draw(self, context):
layout = self.layout
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-12-19 13:33:17 +01:00
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
layout.enabled = rpdat.rp_voxelao
layout.prop(rpdat, 'arm_voxelgi_shadows')
layout.prop(rpdat, 'arm_voxelgi_cones')
layout.prop(rpdat, 'rp_voxelgi_resolution')
layout.prop(rpdat, 'rp_voxelgi_resolution_z')
layout.prop(rpdat, 'arm_voxelgi_dimensions')
layout.prop(rpdat, 'arm_voxelgi_revoxelize')
col2 = layout.column()
2018-12-19 13:33:17 +01:00
col2.enabled = rpdat.arm_voxelgi_revoxelize
col2.prop(rpdat, 'arm_voxelgi_camera')
col2.prop(rpdat, 'arm_voxelgi_temporal')
layout.prop(rpdat, 'arm_voxelgi_occ')
layout.prop(rpdat, 'arm_voxelgi_step')
layout.prop(rpdat, 'arm_voxelgi_range')
layout.prop(rpdat, 'arm_voxelgi_offset')
layout.prop(rpdat, 'arm_voxelgi_aperture')
2018-12-19 13:33:17 +01:00
class ARM_PT_RenderPathWorldPanel(bpy.types.Panel):
2018-12-19 13:33:17 +01:00
bl_label = "World"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_RenderPathPanel"
2018-12-19 13:33:17 +01:00
def draw(self, context):
layout = self.layout
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-12-19 13:33:17 +01:00
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
layout.prop(rpdat, "rp_background")
layout.prop(rpdat, 'arm_irradiance')
col = layout.column()
col.enabled = rpdat.arm_irradiance
col.prop(rpdat, 'arm_radiance')
colb = col.column()
colb.enabled = rpdat.arm_radiance
colb.prop(rpdat, 'arm_radiance_size')
layout.prop(rpdat, 'arm_clouds')
2019-04-29 16:21:44 +02:00
layout.prop(rpdat, "rp_water")
col = layout.column(align=True)
col.enabled = rpdat.rp_water
col.prop(rpdat, 'arm_water_level')
col.prop(rpdat, 'arm_water_density')
col.prop(rpdat, 'arm_water_displace')
col.prop(rpdat, 'arm_water_speed')
col.prop(rpdat, 'arm_water_freq')
col.prop(rpdat, 'arm_water_refract')
col.prop(rpdat, 'arm_water_reflect')
col.prop(rpdat, 'arm_water_color')
2018-12-19 13:33:17 +01:00
class ARM_PT_RenderPathPostProcessPanel(bpy.types.Panel):
2018-12-19 13:33:17 +01:00
bl_label = "Post Process"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_RenderPathPanel"
2018-12-19 13:33:17 +01:00
def draw_header(self, context):
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
self.layout.prop(rpdat, "rp_render_to_texture", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-12-19 13:33:17 +01:00
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
layout.enabled = rpdat.rp_render_to_texture
row = layout.row()
row.prop(rpdat, "rp_antialiasing")
layout.prop(rpdat, "rp_supersampling")
layout.prop(rpdat, 'arm_rp_resolution')
2018-04-20 00:56:54 +02:00
if rpdat.arm_rp_resolution == 'Custom':
2018-12-19 13:33:17 +01:00
layout.prop(rpdat, 'arm_rp_resolution_size')
layout.prop(rpdat, 'arm_rp_resolution_filter')
layout.prop(rpdat, 'rp_dynres')
layout.separator()
row = layout.row()
row.prop(rpdat, "rp_ssgi")
col = layout.column()
col.enabled = rpdat.rp_ssgi != 'Off'
col.prop(rpdat, 'arm_ssgi_half_res')
col.prop(rpdat, 'arm_ssgi_rays')
col.prop(rpdat, 'arm_ssgi_radius')
col.prop(rpdat, 'arm_ssgi_strength')
col.prop(rpdat, 'arm_ssgi_max_steps')
layout.separator()
layout.prop(rpdat, "rp_ssr")
col = layout.column()
col.enabled = rpdat.rp_ssr
col.prop(rpdat, 'arm_ssr_half_res')
col.prop(rpdat, 'arm_ssr_ray_step')
col.prop(rpdat, 'arm_ssr_min_ray_step')
col.prop(rpdat, 'arm_ssr_search_dist')
col.prop(rpdat, 'arm_ssr_falloff_exp')
col.prop(rpdat, 'arm_ssr_jitter')
layout.separator()
layout.prop(rpdat, 'arm_ssrs')
col = layout.column()
col.enabled = rpdat.arm_ssrs
col.prop(rpdat, 'arm_ssrs_ray_step')
2019-05-21 21:53:57 +02:00
layout.prop(rpdat, 'arm_micro_shadowing')
2018-12-19 13:33:17 +01:00
layout.separator()
layout.prop(rpdat, "rp_bloom")
col = layout.column()
col.enabled = rpdat.rp_bloom
col.prop(rpdat, 'arm_bloom_threshold')
col.prop(rpdat, 'arm_bloom_strength')
col.prop(rpdat, 'arm_bloom_radius')
layout.separator()
layout.prop(rpdat, "rp_motionblur")
col = layout.column()
col.enabled = rpdat.rp_motionblur != 'Off'
col.prop(rpdat, 'arm_motion_blur_intensity')
layout.separator()
layout.prop(rpdat, "rp_volumetriclight")
col = layout.column()
col.enabled = rpdat.rp_volumetriclight
col.prop(rpdat, 'arm_volumetric_light_air_color')
col.prop(rpdat, 'arm_volumetric_light_air_turbidity')
col.prop(rpdat, 'arm_volumetric_light_steps')
2019-08-08 20:02:42 +02:00
layout.separator()
layout.prop(rpdat, "rp_chromatic_aberration")
col = layout.column()
col.enabled = rpdat.rp_chromatic_aberration
col.prop(rpdat, 'arm_chromatic_aberration_type')
col.prop(rpdat, 'arm_chromatic_aberration_strength')
if rpdat.arm_chromatic_aberration_type == "Spectral":
col.prop(rpdat, 'arm_chromatic_aberration_samples')
2018-12-19 13:33:17 +01:00
class ARM_PT_RenderPathCompositorPanel(bpy.types.Panel):
2018-12-19 13:33:17 +01:00
bl_label = "Compositor"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "ARM_PT_RenderPathPanel"
2018-12-19 13:33:17 +01:00
def draw_header(self, context):
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
self.layout.prop(rpdat, "rp_compositornodes", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-12-19 13:33:17 +01:00
wrd = bpy.data.worlds['Arm']
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
return
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
layout.enabled = rpdat.rp_compositornodes
layout.prop(rpdat, 'arm_tonemap')
layout.prop(rpdat, 'arm_letterbox')
col = layout.column()
col.enabled = rpdat.arm_letterbox
col.prop(rpdat, 'arm_letterbox_size')
layout.prop(rpdat, 'arm_sharpen')
col = layout.column()
col.enabled = rpdat.arm_sharpen
col.prop(rpdat, 'arm_sharpen_strength')
layout.prop(rpdat, 'arm_fisheye')
layout.prop(rpdat, 'arm_vignette')
2019-02-21 14:20:18 +01:00
col = layout.column()
col.enabled = rpdat.arm_vignette
col.prop(rpdat, 'arm_vignette_strength')
2018-12-19 13:33:17 +01:00
layout.prop(rpdat, 'arm_lensflare')
layout.prop(rpdat, 'arm_grain')
col = layout.column()
col.enabled = rpdat.arm_grain
col.prop(rpdat, 'arm_grain_strength')
layout.prop(rpdat, 'arm_fog')
col = layout.column(align=True)
col.enabled = rpdat.arm_fog
col.prop(rpdat, 'arm_fog_color')
col.prop(rpdat, 'arm_fog_amounta')
col.prop(rpdat, 'arm_fog_amountb')
2018-12-19 13:33:17 +01:00
layout.separator()
layout.prop(rpdat, "rp_autoexposure")
col = layout.column()
col.enabled = rpdat.rp_autoexposure
col.prop(rpdat, 'arm_autoexposure_strength', text='Strength')
2019-05-01 10:52:42 +02:00
col.prop(rpdat, 'arm_autoexposure_speed', text='Speed')
2018-12-19 13:33:17 +01:00
layout.prop(rpdat, 'arm_lens_texture')
2019-08-08 18:56:56 +02:00
if rpdat.arm_lens_texture != "":
layout.prop(rpdat, 'arm_lens_texture_masking')
if rpdat.arm_lens_texture_masking:
layout.prop(rpdat, 'arm_lens_texture_masking_centerMinClip')
layout.prop(rpdat, 'arm_lens_texture_masking_centerMaxClip')
layout.prop(rpdat, 'arm_lens_texture_masking_luminanceMin')
layout.prop(rpdat, 'arm_lens_texture_masking_luminanceMax')
layout.prop(rpdat, 'arm_lens_texture_masking_brightnessExp')
2018-12-19 13:33:17 +01:00
layout.prop(rpdat, 'arm_lut_texture')
2017-08-19 12:10:06 +02:00
class ARM_PT_BakePanel(bpy.types.Panel):
2018-03-05 00:24:04 +01:00
bl_label = "Armory Bake"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
scn = bpy.data.scenes[context.scene.name]
2018-03-13 18:23:00 +01:00
row = layout.row(align=True)
2020-08-23 23:11:49 +02:00
row.prop(scn, "arm_bakemode", expand=True)
2018-03-14 13:24:43 +01:00
2020-08-23 23:11:49 +02:00
if scn.arm_bakemode == "Static Map":
2018-03-13 18:23:00 +01:00
2020-08-23 23:11:49 +02:00
row = layout.row(align=True)
row.alignment = 'EXPAND'
row.operator("arm.bake_textures", icon="RENDER_STILL")
row.operator("arm.bake_apply")
2018-06-11 21:06:30 +02:00
2020-08-23 23:11:49 +02:00
col = layout.column()
col.prop(scn, 'arm_bakelist_scale')
col.prop(scn.cycles, "samples")
2018-03-05 00:24:04 +01:00
2020-08-23 23:11:49 +02:00
layout.prop(scn, 'arm_bakelist_unwrap')
rows = 2
if len(scn.arm_bakelist) > 1:
rows = 4
row = layout.row()
row.template_list("ARM_UL_BakeList", "The_List", scn, "arm_bakelist", scn, "arm_bakelist_index", rows=rows)
col = row.column(align=True)
col.operator("arm_bakelist.new_item", icon='ADD', text="")
col.operator("arm_bakelist.delete_item", icon='REMOVE', text="")
col.menu("ARM_MT_BakeListSpecials", icon='DOWNARROW_HLT', text="")
if len(scn.arm_bakelist) > 1:
col.separator()
op = col.operator("arm_bakelist.move_item", icon='TRIA_UP', text="")
op.direction = 'UP'
op = col.operator("arm_bakelist.move_item", icon='TRIA_DOWN', text="")
op.direction = 'DOWN'
if scn.arm_bakelist_index >= 0 and len(scn.arm_bakelist) > 0:
item = scn.arm_bakelist[scn.arm_bakelist_index]
layout.prop_search(item, "obj", bpy.data, "objects", text="Object")
layout.prop(item, "res_x")
layout.prop(item, "res_y")
2018-03-13 18:23:00 +01:00
2020-08-23 23:11:49 +02:00
else:
2018-03-05 00:24:04 +01:00
2020-08-23 23:11:49 +02:00
scene = context.scene
sceneProperties = scene.TLM_SceneProperties
row = layout.row(align=True)
row = layout.row(align=True)
#We list LuxCoreRender as available, by default we assume Cycles exists
row.prop(sceneProperties, "tlm_lightmap_engine")
if sceneProperties.tlm_lightmap_engine == "Cycles":
#CYCLES SETTINGS HERE
engineProperties = scene.TLM_EngineProperties
row = layout.row(align=True)
row.label(text="General Settings")
row = layout.row(align=True)
row.operator("tlm.build_lightmaps")
row = layout.row(align=True)
row.operator("tlm.clean_lightmaps")
row = layout.row(align=True)
row.operator("tlm.explore_lightmaps")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_apply_on_unwrap")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_headless")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_alert_on_finish")
row = layout.row(align=True)
row.label(text="Cycles Settings")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_quality")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_resolution_scale")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_bake_mode")
if scene.TLM_EngineProperties.tlm_bake_mode == "Background":
row = layout.row(align=True)
row.label(text="Warning! Background mode is currently unstable", icon_value=2)
row = layout.row(align=True)
row.prop(engineProperties, "tlm_caching_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_directional_mode")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_lightmap_savedir")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_dilation_margin")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_exposure_multiplier")
row = layout.row(align=True)
row.prop(engineProperties, "tlm_setting_supersample")
elif sceneProperties.tlm_lightmap_engine == "LuxCoreRender":
#LUXCORE SETTINGS HERE
luxcore_available = False
#Look for Luxcorerender in the renderengine classes
for engine in bpy.types.RenderEngine.__subclasses__():
if engine.bl_idname == "LUXCORE":
luxcore_available = True
break
2018-11-22 13:31:15 +01:00
2020-08-23 23:11:49 +02:00
row = layout.row(align=True)
if not luxcore_available:
row.label(text="Please install BlendLuxCore.")
else:
row.label(text="LuxCoreRender not yet available.")
elif sceneProperties.tlm_lightmap_engine == "OctaneRender":
#LUXCORE SETTINGS HERE
octane_available = False
row = layout.row(align=True)
row.label(text="Octane Render not yet available.")
##################
#DENOISE SETTINGS!
row = layout.row(align=True)
row.label(text="Denoise Settings")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_denoise_use")
row = layout.row(align=True)
if sceneProperties.tlm_denoise_use:
row.prop(sceneProperties, "tlm_denoise_engine", expand=True)
row = layout.row(align=True)
if sceneProperties.tlm_denoise_engine == "Integrated":
row.label(text="No options for Integrated.")
elif sceneProperties.tlm_denoise_engine == "OIDN":
denoiseProperties = scene.TLM_OIDNEngineProperties
row.prop(denoiseProperties, "tlm_oidn_path")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_verbose")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_threads")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_maxmem")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_oidn_affinity")
# row = layout.row(align=True)
# row.prop(denoiseProperties, "tlm_denoise_ao")
elif sceneProperties.tlm_denoise_engine == "Optix":
denoiseProperties = scene.TLM_OptixEngineProperties
row.prop(denoiseProperties, "tlm_optix_path")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_optix_verbose")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_optix_maxmem")
row = layout.row(align=True)
row.prop(denoiseProperties, "tlm_denoise_ao")
##################
#FILTERING SETTINGS!
row = layout.row(align=True)
row.label(text="Filtering Settings")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_filtering_use")
row = layout.row(align=True)
if sceneProperties.tlm_filtering_use:
if sceneProperties.tlm_filtering_engine == "OpenCV":
cv2 = importlib.util.find_spec("cv2")
if cv2 is None:
row = layout.row(align=True)
2020-09-01 18:06:35 +02:00
row.label(text="OpenCV is not installed. Install it below.")
row = layout.row(align=True)
row.label(text="It is recommended to install as administrator.")
row = layout.row(align=True)
row.operator("tlm.install_opencv_lightmaps")
2020-08-23 23:11:49 +02:00
else:
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_mode")
row = layout.row(align=True)
if scene.TLM_SceneProperties.tlm_filtering_mode == "Gaussian":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_gaussian_strength")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Box":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_box_strength")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
elif scene.TLM_SceneProperties.tlm_filtering_mode == "Bilateral":
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_diameter")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_color_deviation")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_bilateral_coordinate_deviation")
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
else:
row.prop(scene.TLM_SceneProperties, "tlm_filtering_median_kernel", expand=True)
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_filtering_iterations")
else:
row = layout.row(align=True)
row.prop(scene.TLM_SceneProperties, "tlm_numpy_filtering_mode")
##################
#ENCODING SETTINGS!
row = layout.row(align=True)
row.label(text="Encoding Settings")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_use")
row = layout.row(align=True)
if sceneProperties.tlm_encoding_use:
row.prop(sceneProperties, "tlm_encoding_mode", expand=True)
if sceneProperties.tlm_encoding_mode == "RGBM" or sceneProperties.tlm_encoding_mode == "RGBD":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_encoding_range")
if sceneProperties.tlm_encoding_mode == "LogLuv":
pass
if sceneProperties.tlm_encoding_mode == "HDR":
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_format")
row = layout.row(align=True)
row.label(text="Encoding Settings")
row = layout.row(align=True)
row = layout.row(align=True)
row.operator("tlm.enable_selection")
row = layout.row(align=True)
row.operator("tlm.disable_selection")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_object_settings")
if sceneProperties.tlm_override_object_settings:
row = layout.row(align=True)
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroup":
if scene.TLM_AtlasList_index >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasList_index]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
else:
row.prop(sceneProperties, "tlm_mesh_lightmap_resolution")
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_unwrap_margin")
row = layout.row(align=True)
row.operator("tlm.remove_uv_selection")
row = layout.row(align=True)
##################
#SELECTION OPERATORS!
row = layout.row(align=True)
row.label(text="Selection Operators")
row = layout.row(align=True)
row = layout.row(align=True)
row.operator("tlm.enable_selection")
row = layout.row(align=True)
row.operator("tlm.disable_selection")
row = layout.row(align=True)
row.prop(sceneProperties, "tlm_override_object_settings")
if sceneProperties.tlm_override_object_settings:
row = layout.row(align=True)
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_lightmap_unwrap_mode")
row = layout.row()
if sceneProperties.tlm_mesh_lightmap_unwrap_mode == "AtlasGroup":
if scene.TLM_AtlasList_index >= 0 and len(scene.TLM_AtlasList) > 0:
row = layout.row()
item = scene.TLM_AtlasList[scene.TLM_AtlasList_index]
row.prop_search(sceneProperties, "tlm_atlas_pointer", scene, "TLM_AtlasList", text='Atlas Group')
else:
row = layout.label(text="Add Atlas Groups from the scene lightmapping settings.")
else:
row.prop(sceneProperties, "tlm_mesh_lightmap_resolution")
row = layout.row()
row.prop(sceneProperties, "tlm_mesh_unwrap_margin")
row = layout.row(align=True)
row.operator("tlm.remove_uv_selection")
row = layout.row(align=True)
2018-03-05 00:24:04 +01:00
2017-08-19 12:10:06 +02:00
class ArmGenLodButton(bpy.types.Operator):
'''Automatically generate LoD levels'''
bl_idname = 'arm.generate_lod'
bl_label = 'Auto Generate'
2017-10-12 20:21:10 +02:00
2017-08-19 12:10:06 +02:00
def lod_name(self, name, level):
return name + '_LOD' + str(level + 1)
def execute(self, context):
obj = context.object
if obj == None:
return{'CANCELLED'}
# Clear
mdata = context.object.data
2017-08-21 12:17:55 +02:00
mdata.arm_lodlist_index = 0
mdata.arm_lodlist.clear()
2017-08-19 12:10:06 +02:00
# Lod levels
wrd = bpy.data.worlds['Arm']
ratio = wrd.arm_lod_gen_ratio
num_levels = wrd.arm_lod_gen_levels
for level in range(0, num_levels):
new_obj = obj.copy()
for i in range(0, 3):
new_obj.location[i] = 0
new_obj.rotation_euler[i] = 0
new_obj.scale[i] = 1
new_obj.data = obj.data.copy()
new_obj.name = self.lod_name(obj.name, level)
new_obj.parent = obj
2019-01-08 22:49:21 +01:00
new_obj.hide_viewport = True
2017-08-19 12:10:06 +02:00
new_obj.hide_render = True
mod = new_obj.modifiers.new('Decimate', 'DECIMATE')
mod.ratio = ratio
ratio *= wrd.arm_lod_gen_ratio
2019-01-08 22:49:21 +01:00
context.scene.collection.objects.link(new_obj)
2017-10-12 20:21:10 +02:00
2017-08-19 12:10:06 +02:00
# Screen sizes
for level in range(0, num_levels):
2017-08-21 12:17:55 +02:00
mdata.arm_lodlist.add()
mdata.arm_lodlist[-1].name = self.lod_name(obj.name, level)
mdata.arm_lodlist[-1].screen_size_prop = (1 - (1 / (num_levels + 1)) * level) - (1 / (num_levels + 1))
2017-08-19 12:10:06 +02:00
return{'FINISHED'}
class ARM_PT_LodPanel(bpy.types.Panel):
2017-08-19 12:10:06 +02:00
bl_label = "Armory Lod"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-08-19 12:10:06 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-08-19 12:10:06 +02:00
obj = bpy.context.object
# Mesh only for now
if obj.type != 'MESH':
return
mdata = obj.data
rows = 2
2017-08-21 12:17:55 +02:00
if len(mdata.arm_lodlist) > 1:
2017-08-19 12:10:06 +02:00
rows = 4
2017-10-12 20:21:10 +02:00
2017-08-19 12:10:06 +02:00
row = layout.row()
2019-03-30 07:48:55 +01:00
row.template_list("ARM_UL_LodList", "The_List", mdata, "arm_lodlist", mdata, "arm_lodlist_index", rows=rows)
2017-08-19 12:10:06 +02:00
col = row.column(align=True)
2018-12-18 23:48:38 +01:00
col.operator("arm_lodlist.new_item", icon='ADD', text="")
col.operator("arm_lodlist.delete_item", icon='REMOVE', text="")
2017-08-19 12:10:06 +02:00
2018-11-22 13:31:15 +01:00
if len(mdata.arm_lodlist) > 1:
col.separator()
op = col.operator("arm_lodlist.move_item", icon='TRIA_UP', text="")
op.direction = 'UP'
op = col.operator("arm_lodlist.move_item", icon='TRIA_DOWN', text="")
op.direction = 'DOWN'
2017-08-21 12:17:55 +02:00
if mdata.arm_lodlist_index >= 0 and len(mdata.arm_lodlist) > 0:
item = mdata.arm_lodlist[mdata.arm_lodlist_index]
2018-12-19 13:33:17 +01:00
layout.prop_search(item, "name", bpy.data, "objects", text="Object")
layout.prop(item, "screen_size_prop")
2018-08-01 10:20:42 +02:00
layout.prop(mdata, "arm_lod_material")
2017-08-19 12:10:06 +02:00
# Auto lod for meshes
if obj.type == 'MESH':
layout.separator()
layout.operator("arm.generate_lod")
wrd = bpy.data.worlds['Arm']
2018-12-19 13:33:17 +01:00
layout.prop(wrd, 'arm_lod_gen_levels')
layout.prop(wrd, 'arm_lod_gen_ratio')
2017-08-19 12:10:06 +02:00
2019-01-17 21:34:38 +01:00
class ArmGenTerrainButton(bpy.types.Operator):
'''Generate terrain sectors'''
bl_idname = 'arm.generate_terrain'
bl_label = 'Generate'
def execute(self, context):
scn = context.scene
if scn == None:
return{'CANCELLED'}
sectors = scn.arm_terrain_sectors
2019-01-20 18:32:52 +01:00
size = scn.arm_terrain_sector_size
height_scale = scn.arm_terrain_height_scale
2019-01-20 18:32:52 +01:00
# Create material
2019-01-17 21:34:38 +01:00
mat = bpy.data.materials.new(name="Terrain")
2019-01-20 18:32:52 +01:00
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
node = nodes.new('ShaderNodeDisplacement')
node.location = (-200, 100)
2019-02-04 21:47:46 +01:00
node.inputs[2].default_value = height_scale
node.space = 'WORLD'
2019-01-20 18:32:52 +01:00
links.new(nodes['Material Output'].inputs[2], node.outputs[0])
node = nodes.new('ShaderNodeTexImage')
node.location = (-600, 100)
node.interpolation = 'Closest'
2019-02-04 21:47:46 +01:00
node.extension = 'EXTEND'
2019-01-20 18:32:52 +01:00
node.arm_material_param = True
node.name = '_TerrainHeight'
node.label = '_TerrainHeight' # Height-map texture link for this sector
links.new(nodes['Displacement'].inputs[0], nodes['_TerrainHeight'].outputs[0])
2019-02-04 21:47:46 +01:00
node = nodes.new('ShaderNodeBump')
node.location = (-200, -200)
node.inputs[0].default_value = 5.0
links.new(nodes['Bump'].inputs[2], nodes['_TerrainHeight'].outputs[0])
links.new(nodes['Principled BSDF'].inputs[17], nodes['Bump'].outputs[0])
2019-01-20 18:32:52 +01:00
# Create sectors
2019-01-17 21:34:38 +01:00
root_obj = bpy.data.objects.new("Terrain", None)
root_obj.location[0] = 0
root_obj.location[1] = 0
root_obj.location[2] = 0
root_obj.arm_export = False
scn.collection.objects.link(root_obj)
scn.arm_terrain_object = root_obj
for i in range(sectors[0] * sectors[1]):
j = str(i + 1).zfill(2)
x = i % sectors[0]
y = int(i / sectors[0])
bpy.ops.mesh.primitive_plane_add(location=(x * size, -y * size, 0))
slice_obj = bpy.context.active_object
slice_obj.scale[0] = size / 2
2019-02-04 21:47:46 +01:00
slice_obj.scale[1] = -(size / 2)
2019-01-17 21:34:38 +01:00
slice_obj.scale[2] = height_scale
slice_obj.data.materials.append(mat)
for p in slice_obj.data.polygons:
p.use_smooth = True
slice_obj.name = 'Terrain.' + j
slice_obj.parent = root_obj
sub_mod = slice_obj.modifiers.new('Subdivision', 'SUBSURF')
sub_mod.subdivision_type = 'SIMPLE'
disp_mod = slice_obj.modifiers.new('Displace', 'DISPLACE')
disp_mod.texture_coords = 'UV'
disp_mod.texture = bpy.data.textures.new(name='Terrain.' + j, type='IMAGE')
disp_mod.texture.extension = 'EXTEND'
disp_mod.texture.use_interpolation = False
disp_mod.texture.use_mipmap = False
disp_mod.texture.image = bpy.data.images.load(filepath=scn.arm_terrain_textures+'/heightmap_' + j + '.png')
f = 1
levels = 0
while f < disp_mod.texture.image.size[0]:
f *= 2
levels += 1
sub_mod.levels = sub_mod.render_levels = levels
return{'FINISHED'}
class ARM_PT_TerrainPanel(bpy.types.Panel):
2019-01-17 21:34:38 +01:00
bl_label = "Armory Terrain"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scn = bpy.context.scene
if scn == None:
return
layout.prop(scn, 'arm_terrain_textures')
layout.prop(scn, 'arm_terrain_sectors')
layout.prop(scn, 'arm_terrain_sector_size')
layout.prop(scn, 'arm_terrain_height_scale')
layout.operator('arm.generate_terrain')
layout.prop(scn, 'arm_terrain_object')
class ARM_PT_TilesheetPanel(bpy.types.Panel):
2017-09-21 18:30:02 +02:00
bl_label = "Armory Tilesheet"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
2017-09-21 18:30:02 +02:00
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-09-21 18:30:02 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-09-21 18:30:02 +02:00
wrd = bpy.data.worlds['Arm']
rows = 2
if len(wrd.arm_tilesheetlist) > 1:
rows = 4
row = layout.row()
2019-03-30 07:48:55 +01:00
row.template_list("ARM_UL_TilesheetList", "The_List", wrd, "arm_tilesheetlist", wrd, "arm_tilesheetlist_index", rows=rows)
2017-09-21 18:30:02 +02:00
col = row.column(align=True)
2018-12-18 23:48:38 +01:00
col.operator("arm_tilesheetlist.new_item", icon='ADD', text="")
col.operator("arm_tilesheetlist.delete_item", icon='REMOVE', text="")
2017-09-21 18:30:02 +02:00
2018-11-22 13:31:15 +01:00
if len(wrd.arm_tilesheetlist) > 1:
col.separator()
op = col.operator("arm_tilesheetlist.move_item", icon='TRIA_UP', text="")
op.direction = 'UP'
op = col.operator("arm_tilesheetlist.move_item", icon='TRIA_DOWN', text="")
op.direction = 'DOWN'
2017-09-21 18:30:02 +02:00
if wrd.arm_tilesheetlist_index >= 0 and len(wrd.arm_tilesheetlist) > 0:
dat = wrd.arm_tilesheetlist[wrd.arm_tilesheetlist_index]
2018-12-19 13:33:17 +01:00
layout.prop(dat, "tilesx_prop")
layout.prop(dat, "tilesy_prop")
2017-09-21 18:30:02 +02:00
layout.prop(dat, "framerate_prop")
2018-09-05 10:20:02 +02:00
layout.label(text='Actions')
2017-09-21 18:30:02 +02:00
rows = 2
if len(dat.arm_tilesheetactionlist) > 1:
rows = 4
row = layout.row()
2019-03-30 07:48:55 +01:00
row.template_list("ARM_UL_TilesheetList", "The_List", dat, "arm_tilesheetactionlist", dat, "arm_tilesheetactionlist_index", rows=rows)
2017-09-21 18:30:02 +02:00
col = row.column(align=True)
2018-12-18 23:48:38 +01:00
col.operator("arm_tilesheetactionlist.new_item", icon='ADD', text="")
col.operator("arm_tilesheetactionlist.delete_item", icon='REMOVE', text="")
2017-09-21 18:30:02 +02:00
2018-11-22 13:31:15 +01:00
if len(dat.arm_tilesheetactionlist) > 1:
col.separator()
op = col.operator("arm_tilesheetactionlist.move_item", icon='TRIA_UP', text="")
op.direction = 'UP'
op = col.operator("arm_tilesheetactionlist.move_item", icon='TRIA_DOWN', text="")
op.direction = 'DOWN'
2017-09-21 18:30:02 +02:00
if dat.arm_tilesheetactionlist_index >= 0 and len(dat.arm_tilesheetactionlist) > 0:
adat = dat.arm_tilesheetactionlist[dat.arm_tilesheetactionlist_index]
2018-12-19 13:33:17 +01:00
layout.prop(adat, "start_prop")
layout.prop(adat, "end_prop")
2017-09-21 18:30:02 +02:00
layout.prop(adat, "loop_prop")
class ARM_PT_ProxyPanel(bpy.types.Panel):
2017-10-10 09:58:03 +02:00
bl_label = "Armory Proxy"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
2017-10-12 20:21:10 +02:00
2017-10-10 09:58:03 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2017-10-10 09:58:03 +02:00
layout.operator("arm.make_proxy")
2017-10-10 12:13:06 +02:00
obj = bpy.context.object
2017-10-16 21:10:33 +02:00
if obj != None and obj.proxy != None:
2018-09-05 10:20:02 +02:00
layout.label(text="Sync")
2018-12-19 13:33:17 +01:00
layout.prop(obj, "arm_proxy_sync_loc")
layout.prop(obj, "arm_proxy_sync_rot")
layout.prop(obj, "arm_proxy_sync_scale")
layout.prop(obj, "arm_proxy_sync_materials")
layout.prop(obj, "arm_proxy_sync_modifiers")
layout.prop(obj, "arm_proxy_sync_traits")
row = layout.row()
row.enabled = obj.arm_proxy_sync_traits
row.prop(obj, "arm_proxy_sync_trait_props")
2018-12-19 13:33:17 +01:00
layout.operator("arm.proxy_toggle_all")
layout.operator("arm.proxy_apply_all")
2017-10-10 09:58:03 +02:00
class ArmMakeProxyButton(bpy.types.Operator):
'''Create proxy from linked object'''
bl_idname = 'arm.make_proxy'
bl_label = 'Make Proxy'
def execute(self, context):
obj = context.object
if obj == None:
return{'CANCELLED'}
2017-10-10 12:13:06 +02:00
if obj.library == None:
2018-03-22 21:43:22 +01:00
self.report({'ERROR'}, 'Select linked object')
2017-10-10 09:58:03 +02:00
arm.proxy.make(obj)
return{'FINISHED'}
2017-10-17 14:24:29 +02:00
class ArmProxyToggleAllButton(bpy.types.Operator):
bl_idname = 'arm.proxy_toggle_all'
bl_label = 'Toggle All'
2017-10-16 21:10:33 +02:00
def execute(self, context):
2017-10-17 13:39:50 +02:00
obj = context.object
b = not obj.arm_proxy_sync_loc
obj.arm_proxy_sync_loc = b
obj.arm_proxy_sync_rot = b
obj.arm_proxy_sync_scale = b
obj.arm_proxy_sync_materials = b
obj.arm_proxy_sync_modifiers = b
obj.arm_proxy_sync_traits = b
obj.arm_proxy_sync_trait_props = b
2017-10-16 21:10:33 +02:00
return{'FINISHED'}
2017-10-17 13:39:50 +02:00
class ArmProxyApplyAllButton(bpy.types.Operator):
bl_idname = 'arm.proxy_apply_all'
bl_label = 'Apply to All'
2020-04-12 20:04:28 +02:00
2017-10-16 21:10:33 +02:00
def execute(self, context):
2017-10-17 13:39:50 +02:00
for obj in bpy.data.objects:
if obj.proxy == None:
continue
if obj.proxy == context.object.proxy:
obj.arm_proxy_sync_loc = context.object.arm_proxy_sync_loc
obj.arm_proxy_sync_rot = context.object.arm_proxy_sync_rot
obj.arm_proxy_sync_scale = context.object.arm_proxy_sync_scale
obj.arm_proxy_sync_materials = context.object.arm_proxy_sync_materials
obj.arm_proxy_sync_modifiers = context.object.arm_proxy_sync_modifiers
obj.arm_proxy_sync_traits = context.object.arm_proxy_sync_traits
obj.arm_proxy_sync_trait_props = context.object.arm_proxy_sync_trait_props
2017-10-16 21:10:33 +02:00
return{'FINISHED'}
2017-10-17 13:39:50 +02:00
class ArmSyncProxyButton(bpy.types.Operator):
bl_idname = 'arm.sync_proxy'
bl_label = 'Sync'
2017-10-16 21:10:33 +02:00
def execute(self, context):
2017-10-17 13:39:50 +02:00
if len(bpy.data.libraries) > 0:
2017-10-16 21:10:33 +02:00
for obj in bpy.data.objects:
2017-10-18 10:20:37 +02:00
if obj == None or obj.proxy == None:
continue
2017-10-17 13:39:50 +02:00
if obj.arm_proxy_sync_loc:
arm.proxy.sync_location(obj)
if obj.arm_proxy_sync_rot:
arm.proxy.sync_rotation(obj)
if obj.arm_proxy_sync_scale:
arm.proxy.sync_scale(obj)
if obj.arm_proxy_sync_materials:
arm.proxy.sync_materials(obj)
if obj.arm_proxy_sync_modifiers:
arm.proxy.sync_modifiers(obj)
if obj.arm_proxy_sync_traits:
arm.proxy.sync_traits(obj)
print('Armory: Proxy objects synchronized')
2017-10-16 21:10:33 +02:00
return{'FINISHED'}
2017-12-03 12:30:14 +01:00
class ArmPrintTraitsButton(bpy.types.Operator):
bl_idname = 'arm.print_traits'
bl_label = 'Print Traits'
def execute(self, context):
2017-12-03 13:04:24 +01:00
for s in bpy.data.scenes:
2017-12-03 13:28:30 +01:00
print(s.name + ' traits:')
2017-12-03 13:04:24 +01:00
for o in s.objects:
for t in o.arm_traitlist:
2017-12-04 09:40:58 +01:00
if not t.enabled_prop:
continue
tname = t.node_tree_prop.name if t.type_prop == 'Logic Nodes' else t.class_name_prop
2017-12-03 13:04:24 +01:00
print('Object {0} - {1}'.format(o.name, tname))
2017-12-03 12:30:14 +01:00
return{'FINISHED'}
class ARM_PT_MaterialNodePanel(bpy.types.Panel):
2018-06-12 00:26:52 +02:00
bl_label = 'Armory Material Node'
bl_idname = 'ARM_PT_MaterialNodePanel'
2018-06-12 00:26:52 +02:00
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
2018-12-19 15:47:58 +01:00
bl_category = 'Node'
2018-06-12 00:26:52 +02:00
2020-10-11 00:24:11 +02:00
@classmethod
def poll(cls, context):
return (context.space_data.tree_type == 'ShaderNodeTree'
and context.space_data.edit_tree
and context.space_data.shader_type == 'OBJECT')
2018-06-12 00:26:52 +02:00
def draw(self, context):
layout = self.layout
2018-12-19 13:33:17 +01:00
layout.use_property_split = True
2018-12-19 20:10:34 +01:00
layout.use_property_decorate = False
2018-06-12 00:26:52 +02:00
n = context.active_node
if n != None and (n.bl_idname == 'ShaderNodeRGB' or n.bl_idname == 'ShaderNodeValue' or n.bl_idname == 'ShaderNodeTexImage'):
layout.prop(context.active_node, 'arm_material_param')
class ARM_OT_ShowFileVersionInfo(bpy.types.Operator):
bl_label = 'Show old file version info'
bl_idname = 'arm.show_old_file_version_info'
bl_description = ('Displays an info panel that warns about opening a file'
'which was created in a previous version of Armory')
# bl_options = {'INTERNAL'}
wrd = None
def draw_message_box(self, context):
file_version = ARM_OT_ShowFileVersionInfo.wrd.arm_version
current_version = props.arm_version
layout = self.layout
layout = layout.column(align=True)
layout.alignment = 'EXPAND'
if current_version == file_version:
layout.label('This file was saved in', icon='INFO')
layout.label('the current Armory version', icon='BLANK1')
layout.separator()
layout.label(f'(version: {current_version}')
row = layout.row(align=True)
row.active_default = True
row.operator('arm.discard_popup', text='Ok')
# this will help order versions better, somewhat.
# note: this is NOT complete
current_version = tuple( current_version.split('.') )
file_version = tuple( file_version.split('.') )
if current_version > file_version:
layout.label(text='Warning: This file was saved in a', icon='ERROR')
layout.label(text='previous version of Armory!', icon='BLANK1')
layout.separator()
layout.label(text='Please inform yourself about breaking changes!', icon='BLANK1')
layout.label(text=f'File saved in: {file_version}', icon='BLANK1')
layout.label(text=f'Current version: {current_version}', icon='BLANK1')
layout.separator()
layout.separator()
layout.label(text='Should Armory try to automatically update', icon='BLANK1')
layout.label(text='the file to the current SDK version?', icon='BLANK1')
layout.separator()
row = layout.row(align=True)
row.active_default = True
row.operator('arm.update_file_sdk', text='Yes')
row.active_default = False
row.operator('arm.discard_popup', text='No')
else:
layout.label(text='Warning: This file was saved in a', icon='ERROR')
layout.label(text='future version of Armory!', icon='BLANK1')
layout.separator()
layout.label(text='It is impossible to downgrade a file,', icon='BLANK1')
layout.label(text='Something will probably be broken here.', icon='BLANK1')
layout.label(text=f'File saved in: {file_version}', icon='BLANK1')
layout.label(text=f'Current version: {current_version}', icon='BLANK1')
layout.separator()
layout.separator()
layout.label(text='Please check how this file was created', icon='BLANK1')
layout.separator()
row = layout.row(align=True)
row.active_default = True
row.operator('arm.discard_popup', text='Ok')
def execute(self, context):
ARM_OT_ShowFileVersionInfo.wrd = bpy.data.worlds['Arm']
context.window_manager.popover(ARM_OT_ShowFileVersionInfo.draw_message_box, ui_units_x=16)
return {"FINISHED"}
class ARM_OT_ShowNodeUpdateErrors(bpy.types.Operator):
bl_label = 'Show upgrade failure details'
bl_idname = 'arm.show_node_update_errors'
bl_description = ('Displays an info panel that shows the different errors that occurred when upgrading nodes')
wrd = None # a helper internal variable
def draw_message_box(self, context):
list_of_errors = arm.nodes_logic.replacement_errors.copy()
# note: list_of_errors is a set of tuples: `(error_type, node_class, tree_name)`
# where `error_type` can be "unregistered", "update failed", "future version", "bad version", or "misc."
file_version = ARM_OT_ShowNodeUpdateErrors.wrd.arm_version
current_version = props.arm_version
# this will help order versions better, somewhat.
# note: this is NOT complete
current_version_2 = tuple( current_version.split('.') )
file_version_2 = tuple( file_version.split('.') )
is_armory_upgrade = (current_version_2 > file_version_2)
error_types = set()
errored_trees = set()
errored_nodes = set()
for error_entry in list_of_errors:
error_types.add(error_entry[0])
errored_nodes.add(error_entry[1])
errored_trees.add(error_entry[2])
layout = self.layout
layout = layout.column(align=True)
layout.alignment = 'EXPAND'
layout.label(text="Some nodes failed to be updated to the current armory version", icon="ERROR")
if current_version==file_version:
layout.label(text="(This might be because you are using a development snapshot, or a homemade version ;) )", icon='BLANK1')
elif not is_armory_upgrade:
layout.label(text="(Please note that it is not possible do downgrade nodes to a previous version either.", icon='BLANK1')
layout.label(text="This might be the cause of your problem.)", icon='BLANK1')
layout.label(text=f'File saved in: {file_version}', icon='BLANK1')
layout.label(text=f'Current version: {current_version}', icon='BLANK1')
layout.separator()
if 'update failed' in error_types:
layout.label(text="Some nodes do not have an update procedure to deal with the version saved in this file.", icon='BLANK1')
if current_version==file_version:
layout.label(text="(if you are a developer, this might be because you didn't implement it yet.)", icon='BLANK1')
if 'bad version' in error_types:
layout.label(text="Some nodes do not have version information attached to them.", icon='BLANK1')
if 'unregistered' in error_types:
if is_armory_upgrade:
layout.label(text='Some nodes seem to be too old to be understood by armory anymore', icon='BLANK1')
else:
layout.label(text="Some nodes are unknown to armory, either because they are too new or too old.", icon='BLANK1')
if 'future version' in error_types:
if is_armory_upgrade:
layout.label(text='Somehow, some nodes seem to have been created with a future version of armory.', icon='BLANK1')
else:
layout.label(text='Some nodes seem to have been created with a future version of armory.', icon='BLANK1')
if 'misc.' in error_types:
layout.label(text="Some nodes' update procedure failed to complete")
layout.separator()
layout.label(text='the nodes impacted are the following:', icon='BLANK1')
for node in errored_nodes:
layout.label(text=f' {node}', icon='BLANK1')
layout.separator()
layout.label(text='the node trees impacted are the following:', icon='BLANK1')
for tree in errored_trees:
layout.label(text=f' "{tree}"', icon='BLANK1')
layout.separator()
layout.label(text="A detailed error report has been saved next to the blender file.", icon='BLANK1')
layout.label(text="the file name is \"node_update_failure\", followed by the current time.", icon='BLANK1')
layout.separator()
row = layout.row(align=True)
row.active_default = False
row.operator('arm.discard_popup', text='Ok')
def execute(self, context):
ARM_OT_ShowNodeUpdateErrors.wrd = bpy.data.worlds['Arm']
context.window_manager.popover(ARM_OT_ShowNodeUpdateErrors.draw_message_box, ui_units_x=32)
return {"FINISHED"}
class ARM_OT_UpdateFileSDK(bpy.types.Operator):
bl_idname = 'arm.update_file_sdk'
bl_label = 'Update file to current SDK version'
bl_description = bl_label
bl_options = {'INTERNAL'}
def execute(self, context):
wrd = bpy.data.worlds['Arm']
# This allows for seamless migration from ealier versions of Armory
for rp in wrd.arm_rplist: # TODO: deprecated
if rp.rp_gi != 'Off':
rp.rp_gi = 'Off'
rp.rp_voxelao = True
# Replace deprecated nodes
arm.nodes_logic.replaceAll()
wrd.arm_version = props.arm_version
wrd.arm_commit = props.arm_commit
arm.make.clean()
print(f'Project updated to SDK {props.arm_version}. Please save the .blend file.')
return {'FINISHED'}
2020-08-10 00:23:26 +02:00
class ARM_OT_DiscardPopup(bpy.types.Operator):
"""Empty operator for discarding dialogs."""
bl_idname = 'arm.discard_popup'
bl_label = 'OK'
bl_description = 'Discard'
bl_options = {'INTERNAL'}
def execute(self, context):
return {'FINISHED'}
class ArmoryUpdateListAndroidEmulatorButton(bpy.types.Operator):
'''Updating the list of emulators for the Android platform'''
bl_idname = 'arm.update_list_android_emulator'
bl_label = 'Update List Emulators'
def execute(self, context):
if not arm.utils.check_saved(self):
return {"CANCELLED"}
if not arm.utils.check_sdkpath(self):
return {"CANCELLED"}
if len(arm.utils.get_android_sdk_root_path()) == 0:
return {"CANCELLED"}
os.environ['ANDROID_SDK_ROOT'] = arm.utils.get_android_sdk_root_path()
items, err = arm.utils.get_android_emulators_list()
if len(err) > 0:
print('Update List Emulators Warning: File "'+ arm.utils.get_android_emulator_file() +'" not found. Check that the variable ANDROID_SDK_ROOT is correct in environment variables or in "Android SDK Path" setting: \n- If you specify an environment variable ANDROID_SDK_ROOT, then you need to restart Blender;\n- If you specify the setting "Android SDK Path", then repeat operation "Publish"')
return{'FINISHED'}
items_enum = []
for i in items:
items_enum.append((i, i, i))
bpy.types.World.arm_project_android_list_avd = EnumProperty(items=items_enum, name="Emulator", update=assets.invalidate_compiler_cache)
return{'FINISHED'}
class ArmoryUpdateListAndroidEmulatorRunButton(bpy.types.Operator):
'''Launch Android emulator selected from the list'''
bl_idname = 'arm.run_android_emulator'
bl_label = 'Launch Emulator'
def execute(self, context):
if not arm.utils.check_saved(self):
return {"CANCELLED"}
if not arm.utils.check_sdkpath(self):
return {"CANCELLED"}
if len(arm.utils.get_android_sdk_root_path()) == 0:
return {"CANCELLED"}
make.run_android_emulators(arm.utils.get_android_emulator_name())
return{'FINISHED'}
2020-08-10 00:23:26 +02:00
2016-10-19 13:28:06 +02:00
def register():
bpy.utils.register_class(ARM_PT_ObjectPropsPanel)
bpy.utils.register_class(ARM_PT_ModifiersPropsPanel)
bpy.utils.register_class(ARM_PT_ParticlesPropsPanel)
bpy.utils.register_class(ARM_PT_PhysicsPropsPanel)
bpy.utils.register_class(ARM_PT_DataPropsPanel)
bpy.utils.register_class(ARM_PT_ScenePropsPanel)
bpy.utils.register_class(ARM_PT_WorldPropsPanel)
2017-03-15 12:30:14 +01:00
bpy.utils.register_class(InvalidateCacheButton)
bpy.utils.register_class(InvalidateMaterialCacheButton)
bpy.utils.register_class(ARM_PT_MaterialPropsPanel)
bpy.utils.register_class(ARM_PT_MaterialBlendingPropsPanel)
bpy.utils.register_class(ARM_PT_ArmoryPlayerPanel)
bpy.utils.register_class(ARM_PT_ArmoryExporterPanel)
Add Android Settings + LN Set Vibrate 1. For the new settings to fully function, you need to update the submodules so that this Pull Request (https://github.com/Kode/kincmake/pull/100) gets into armsdk. Extended settings via khafile.js. 2. Added Android Settings panel: - invisible until the target platform android-hl is added to the list; - inactive until the target platform android-hl is selected in the list. Options: - Orientation; - Compile Version SDK - from 26 to 30, default 29; - Minimal Version SDK - from 14 to 30, default 14; - Target Version SDK - from 26 to 30, default 29; - Permissions - a list of permissions. If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty; - Android ABI Filters - a list of platforms to build for (arm64-v8a, armeabi-v7a, x86, x86_64). If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty. If the list is empty, then all platforms will be used (as before). 3. The enum (names of permissions) and the function have been added to the utils.py modules, which adds the specified value to the list of permissions. Feature added for ease of use from different locations (different logical nodes). 4. List of permissions: - ACCESS_COARSE_LOCATION - Allows an app to access approximate location; - ACCESS_NETWORK_STATE - Allows applications to access information about networks; - ACCESS_FINE_LOCATION - Allows an app to access precise location; - ACCESS_WIFI_STATE - Allows applications to access information about Wi-Fi network; - BLUETOOTH - Allows applications to connect to paired bluetooth devices; - BLUETOOTH_ADMIN - Allows applications to discover and pair bluetooth devices; - CAMERA - Required to be able to access the camera device; - EXPAND_STATUS_BAR - Allows an application to expand or collapse the status bar; - FOREGROUND_SERVICE - Allows a regular application to use Service.startForeground; - GET_ACCOUNTS - Allows access to the list of accounts in the Accounts Service; - INTERNET - Allows applications to open network sockets'; - READ_EXTERNAL_STORAGE - Allows an application to read from external storage; - VIBRATE - Allows access to the vibrator; - WRITE_EXTERNAL_STORAGE - Allows an application to write to external storage. 5. Added logical node Set Vibrate: Category: Native Pulses the vibration hardware on the device for time in milliseconds, if such hardware exists. Input parameters: - Milliseconds - time in milliseconds (data type Int, default value 100). When adding the logical node Set Vibrate, the permission is automatically added to the list, even if the target android-hl has not been added to the export list (using a function from utils.py).
2020-10-17 15:47:54 +02:00
bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidSettingsPanel)
bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidPermissionsPanel)
bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidAbiPanel)
bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidBuildAPKPanel)
bpy.utils.register_class(ARM_PT_ArmoryProjectPanel)
bpy.utils.register_class(ARM_PT_ProjectFlagsPanel)
bpy.utils.register_class(ARM_PT_ProjectFlagsDebugConsolePanel)
bpy.utils.register_class(ARM_PT_ProjectWindowPanel)
bpy.utils.register_class(ARM_PT_ProjectModulesPanel)
bpy.utils.register_class(ARM_PT_RenderPathPanel)
bpy.utils.register_class(ARM_PT_RenderPathRendererPanel)
bpy.utils.register_class(ARM_PT_RenderPathShadowsPanel)
bpy.utils.register_class(ARM_PT_RenderPathVoxelsPanel)
bpy.utils.register_class(ARM_PT_RenderPathWorldPanel)
bpy.utils.register_class(ARM_PT_RenderPathPostProcessPanel)
bpy.utils.register_class(ARM_PT_RenderPathCompositorPanel)
bpy.utils.register_class(ARM_PT_BakePanel)
2017-08-19 03:08:42 +02:00
# bpy.utils.register_class(ArmVirtualInputPanel)
2017-03-15 12:30:14 +01:00
bpy.utils.register_class(ArmoryPlayButton)
bpy.utils.register_class(ArmoryStopButton)
bpy.utils.register_class(ArmoryBuildProjectButton)
bpy.utils.register_class(ArmoryOpenProjectFolderButton)
bpy.utils.register_class(ArmoryOpenEditorButton)
2017-03-15 12:30:14 +01:00
bpy.utils.register_class(CleanMenu)
bpy.utils.register_class(CleanButtonMenu)
bpy.utils.register_class(ArmoryCleanProjectButton)
2017-09-04 12:14:14 +02:00
bpy.utils.register_class(ArmoryPublishProjectButton)
2017-08-19 12:10:06 +02:00
bpy.utils.register_class(ArmGenLodButton)
bpy.utils.register_class(ARM_PT_LodPanel)
2019-01-17 21:34:38 +01:00
bpy.utils.register_class(ArmGenTerrainButton)
bpy.utils.register_class(ARM_PT_TerrainPanel)
bpy.utils.register_class(ARM_PT_TilesheetPanel)
bpy.utils.register_class(ARM_PT_ProxyPanel)
2017-10-10 09:58:03 +02:00
bpy.utils.register_class(ArmMakeProxyButton)
2017-10-17 14:24:29 +02:00
bpy.utils.register_class(ArmProxyToggleAllButton)
2017-10-17 13:39:50 +02:00
bpy.utils.register_class(ArmProxyApplyAllButton)
bpy.utils.register_class(ArmSyncProxyButton)
2017-12-03 12:30:14 +01:00
bpy.utils.register_class(ArmPrintTraitsButton)
bpy.utils.register_class(ARM_PT_MaterialNodePanel)
bpy.utils.register_class(ARM_OT_UpdateFileSDK)
bpy.utils.register_class(ARM_OT_ShowFileVersionInfo)
bpy.utils.register_class(ARM_OT_ShowNodeUpdateErrors)
2020-08-10 00:23:26 +02:00
bpy.utils.register_class(ARM_OT_DiscardPopup)
bpy.utils.register_class(ArmoryUpdateListAndroidEmulatorButton)
bpy.utils.register_class(ArmoryUpdateListAndroidEmulatorRunButton)
2020-08-10 00:23:26 +02:00
2016-10-19 13:28:06 +02:00
bpy.types.VIEW3D_HT_header.append(draw_view3d_header)
2020-08-10 00:23:26 +02:00
bpy.types.VIEW3D_MT_object.append(draw_view3d_object_menu)
2016-10-19 13:28:06 +02:00
def unregister():
2020-08-10 00:23:26 +02:00
bpy.types.VIEW3D_MT_object.remove(draw_view3d_object_menu)
2016-10-19 13:28:06 +02:00
bpy.types.VIEW3D_HT_header.remove(draw_view3d_header)
bpy.utils.unregister_class(ArmoryUpdateListAndroidEmulatorRunButton)
bpy.utils.unregister_class(ArmoryUpdateListAndroidEmulatorButton)
2020-08-10 00:23:26 +02:00
bpy.utils.unregister_class(ARM_OT_DiscardPopup)
bpy.utils.unregister_class(ARM_OT_ShowNodeUpdateErrors)
bpy.utils.unregister_class(ARM_OT_ShowFileVersionInfo)
bpy.utils.unregister_class(ARM_OT_UpdateFileSDK)
bpy.utils.unregister_class(ARM_PT_ObjectPropsPanel)
bpy.utils.unregister_class(ARM_PT_ModifiersPropsPanel)
bpy.utils.unregister_class(ARM_PT_ParticlesPropsPanel)
bpy.utils.unregister_class(ARM_PT_PhysicsPropsPanel)
bpy.utils.unregister_class(ARM_PT_DataPropsPanel)
bpy.utils.unregister_class(ARM_PT_WorldPropsPanel)
bpy.utils.unregister_class(ARM_PT_ScenePropsPanel)
2017-03-15 12:30:14 +01:00
bpy.utils.unregister_class(InvalidateCacheButton)
bpy.utils.unregister_class(InvalidateMaterialCacheButton)
bpy.utils.unregister_class(ARM_PT_MaterialPropsPanel)
bpy.utils.unregister_class(ARM_PT_MaterialBlendingPropsPanel)
bpy.utils.unregister_class(ARM_PT_ArmoryPlayerPanel)
bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidBuildAPKPanel)
Add Android Settings + LN Set Vibrate 1. For the new settings to fully function, you need to update the submodules so that this Pull Request (https://github.com/Kode/kincmake/pull/100) gets into armsdk. Extended settings via khafile.js. 2. Added Android Settings panel: - invisible until the target platform android-hl is added to the list; - inactive until the target platform android-hl is selected in the list. Options: - Orientation; - Compile Version SDK - from 26 to 30, default 29; - Minimal Version SDK - from 14 to 30, default 14; - Target Version SDK - from 26 to 30, default 29; - Permissions - a list of permissions. If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty; - Android ABI Filters - a list of platforms to build for (arm64-v8a, armeabi-v7a, x86, x86_64). If I will duplicate entries in the list, then only unique entries will be included during export. By default, the list is empty. If the list is empty, then all platforms will be used (as before). 3. The enum (names of permissions) and the function have been added to the utils.py modules, which adds the specified value to the list of permissions. Feature added for ease of use from different locations (different logical nodes). 4. List of permissions: - ACCESS_COARSE_LOCATION - Allows an app to access approximate location; - ACCESS_NETWORK_STATE - Allows applications to access information about networks; - ACCESS_FINE_LOCATION - Allows an app to access precise location; - ACCESS_WIFI_STATE - Allows applications to access information about Wi-Fi network; - BLUETOOTH - Allows applications to connect to paired bluetooth devices; - BLUETOOTH_ADMIN - Allows applications to discover and pair bluetooth devices; - CAMERA - Required to be able to access the camera device; - EXPAND_STATUS_BAR - Allows an application to expand or collapse the status bar; - FOREGROUND_SERVICE - Allows a regular application to use Service.startForeground; - GET_ACCOUNTS - Allows access to the list of accounts in the Accounts Service; - INTERNET - Allows applications to open network sockets'; - READ_EXTERNAL_STORAGE - Allows an application to read from external storage; - VIBRATE - Allows access to the vibrator; - WRITE_EXTERNAL_STORAGE - Allows an application to write to external storage. 5. Added logical node Set Vibrate: Category: Native Pulses the vibration hardware on the device for time in milliseconds, if such hardware exists. Input parameters: - Milliseconds - time in milliseconds (data type Int, default value 100). When adding the logical node Set Vibrate, the permission is automatically added to the list, even if the target android-hl has not been added to the export list (using a function from utils.py).
2020-10-17 15:47:54 +02:00
bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidAbiPanel)
bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidPermissionsPanel)
bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidSettingsPanel)
bpy.utils.unregister_class(ARM_PT_ArmoryExporterPanel)
bpy.utils.unregister_class(ARM_PT_ArmoryProjectPanel)
bpy.utils.unregister_class(ARM_PT_ProjectFlagsDebugConsolePanel)
bpy.utils.unregister_class(ARM_PT_ProjectFlagsPanel)
bpy.utils.unregister_class(ARM_PT_ProjectWindowPanel)
bpy.utils.unregister_class(ARM_PT_ProjectModulesPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathRendererPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathShadowsPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathVoxelsPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathWorldPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathPostProcessPanel)
bpy.utils.unregister_class(ARM_PT_RenderPathCompositorPanel)
bpy.utils.unregister_class(ARM_PT_BakePanel)
2017-08-19 03:08:42 +02:00
# bpy.utils.unregister_class(ArmVirtualInputPanel)
2017-03-15 12:30:14 +01:00
bpy.utils.unregister_class(ArmoryPlayButton)
bpy.utils.unregister_class(ArmoryStopButton)
bpy.utils.unregister_class(ArmoryBuildProjectButton)
bpy.utils.unregister_class(ArmoryOpenProjectFolderButton)
bpy.utils.unregister_class(ArmoryOpenEditorButton)
2017-03-15 12:30:14 +01:00
bpy.utils.unregister_class(CleanMenu)
bpy.utils.unregister_class(CleanButtonMenu)
bpy.utils.unregister_class(ArmoryCleanProjectButton)
2017-09-04 12:14:14 +02:00
bpy.utils.unregister_class(ArmoryPublishProjectButton)
2017-08-19 12:10:06 +02:00
bpy.utils.unregister_class(ArmGenLodButton)
bpy.utils.unregister_class(ARM_PT_LodPanel)
2019-01-17 21:34:38 +01:00
bpy.utils.unregister_class(ArmGenTerrainButton)
bpy.utils.unregister_class(ARM_PT_TerrainPanel)
bpy.utils.unregister_class(ARM_PT_TilesheetPanel)
bpy.utils.unregister_class(ARM_PT_ProxyPanel)
2017-10-10 09:58:03 +02:00
bpy.utils.unregister_class(ArmMakeProxyButton)
2017-10-17 14:24:29 +02:00
bpy.utils.unregister_class(ArmProxyToggleAllButton)
2017-10-17 13:39:50 +02:00
bpy.utils.unregister_class(ArmProxyApplyAllButton)
bpy.utils.unregister_class(ArmSyncProxyButton)
2017-12-03 12:30:14 +01:00
bpy.utils.unregister_class(ArmPrintTraitsButton)
bpy.utils.unregister_class(ARM_PT_MaterialNodePanel)