2016-10-19 13:28:06 +02:00
|
|
|
import bpy
|
|
|
|
import time
|
2017-02-09 22:52:47 +01:00
|
|
|
import os
|
|
|
|
import sys
|
2016-10-31 19:29:03 +01:00
|
|
|
from bpy.app.handlers import persistent
|
2017-03-15 12:30:14 +01:00
|
|
|
import arm.utils
|
|
|
|
import arm.bridge as bridge
|
|
|
|
import arm.log as log
|
|
|
|
import arm.props as props
|
|
|
|
import arm.make as make
|
|
|
|
import arm.make_state as state
|
|
|
|
import arm.space_armory as space_armory
|
|
|
|
import arm.make_renderer as make_renderer
|
2016-10-19 13:28:06 +02:00
|
|
|
try:
|
|
|
|
import barmory
|
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
last_time = time.time()
|
2016-11-25 11:29:26 +01:00
|
|
|
# last_update_time = time.time()
|
2016-10-19 13:28:06 +02:00
|
|
|
last_operator = None
|
2016-11-23 15:34:59 +01:00
|
|
|
redraw_ui = False
|
|
|
|
redraw_progress = False
|
2017-04-01 21:25:57 +02:00
|
|
|
first_update = True
|
2016-10-19 13:28:06 +02:00
|
|
|
|
2016-10-31 19:29:03 +01:00
|
|
|
@persistent
|
2016-10-19 13:28:06 +02:00
|
|
|
def on_scene_update_post(context):
|
|
|
|
global last_time
|
2016-11-25 11:29:26 +01:00
|
|
|
# global last_update_time
|
2016-10-19 13:28:06 +02:00
|
|
|
global last_operator
|
2016-11-23 15:34:59 +01:00
|
|
|
global redraw_ui
|
|
|
|
global redraw_progress
|
2017-04-01 21:25:57 +02:00
|
|
|
global first_update
|
|
|
|
|
|
|
|
if first_update == True: # Skip first one, object reports is_update_data
|
|
|
|
first_update = False
|
|
|
|
return
|
2016-10-19 13:28:06 +02:00
|
|
|
|
2016-11-23 15:34:59 +01:00
|
|
|
# Redraw at the start of 'next' frame
|
|
|
|
if redraw_ui and bpy.context.screen != None:
|
|
|
|
for area in bpy.context.screen.areas:
|
|
|
|
if area.type == 'VIEW_3D' or area.type == 'PROPERTIES':
|
|
|
|
area.tag_redraw()
|
|
|
|
redraw_ui = False
|
|
|
|
if redraw_progress and bpy.context.screen != None:
|
|
|
|
for area in bpy.context.screen.areas:
|
|
|
|
if area.type == 'INFO':
|
|
|
|
area.tag_redraw()
|
|
|
|
break
|
2016-11-25 11:29:26 +01:00
|
|
|
redraw_progress = False
|
2016-11-23 15:34:59 +01:00
|
|
|
|
|
|
|
# New operator
|
2016-11-07 00:31:48 +01:00
|
|
|
ops = bpy.context.window_manager.operators
|
|
|
|
operators_changed = False
|
|
|
|
if len(ops) > 0 and last_operator != ops[-1]:
|
|
|
|
last_operator = ops[-1]
|
|
|
|
operators_changed = True
|
2017-02-15 16:55:46 +01:00
|
|
|
# Undo was performed - Blender clears the complete operator stack, undo last known operator atleast
|
2017-02-17 20:06:57 +01:00
|
|
|
# if len(ops) == 0 and last_operator != None:
|
|
|
|
# if hasattr(bpy.context, 'object'):
|
|
|
|
# op_changed(last_operator, bpy.context.object)
|
|
|
|
# last_operator = None
|
2016-11-07 00:31:48 +01:00
|
|
|
|
2016-11-23 15:34:59 +01:00
|
|
|
# Player running
|
|
|
|
state.krom_running = False
|
|
|
|
if not state.is_paused and bpy.context.screen != None:
|
|
|
|
for area in bpy.context.screen.areas:
|
|
|
|
if area.type == 'VIEW_ARMORY':
|
|
|
|
state.krom_running = True
|
|
|
|
break
|
2016-10-19 13:28:06 +02:00
|
|
|
|
2016-11-23 15:34:59 +01:00
|
|
|
# Auto patch on every operator change
|
2017-01-18 14:52:51 +01:00
|
|
|
wrd = bpy.data.worlds['Arm']
|
2016-11-23 15:34:59 +01:00
|
|
|
if state.krom_running and \
|
2017-01-18 14:52:51 +01:00
|
|
|
wrd.arm_play_live_patch and \
|
|
|
|
wrd.arm_play_auto_build and \
|
2016-11-23 15:34:59 +01:00
|
|
|
operators_changed:
|
|
|
|
# Otherwise rebuild scene
|
|
|
|
if bridge.send_operator(last_operator) == False:
|
2017-01-18 14:52:51 +01:00
|
|
|
make.play_project(in_viewport=True)
|
2016-10-19 13:28:06 +02:00
|
|
|
|
2016-11-23 15:34:59 +01:00
|
|
|
# Use frame rate for update frequency for now
|
|
|
|
if time.time() - last_time >= (1 / bpy.context.scene.render.fps):
|
|
|
|
last_time = time.time()
|
2016-10-19 13:28:06 +02:00
|
|
|
|
2016-11-23 15:34:59 +01:00
|
|
|
if state.krom_running:
|
|
|
|
# Read krom console
|
|
|
|
if barmory.get_console_updated() == 1:
|
|
|
|
log.print_player(barmory.get_console())
|
|
|
|
# Read operator console
|
|
|
|
if barmory.get_operator_updated() == 1:
|
|
|
|
bridge.parse_operator(barmory.get_operator())
|
|
|
|
# Tag redraw
|
|
|
|
if bpy.context.screen != None:
|
|
|
|
for area in bpy.context.screen.areas:
|
|
|
|
if area.type == 'VIEW_ARMORY':
|
2016-10-19 13:28:06 +02:00
|
|
|
area.tag_redraw()
|
2016-11-23 15:34:59 +01:00
|
|
|
break
|
2016-10-19 13:28:06 +02:00
|
|
|
|
|
|
|
# New output has been logged
|
2016-11-13 11:46:54 +01:00
|
|
|
if log.tag_redraw and bpy.context.screen != None:
|
2016-10-19 13:28:06 +02:00
|
|
|
log.tag_redraw = False
|
2016-11-23 15:34:59 +01:00
|
|
|
redraw_progress = True
|
2016-10-19 13:28:06 +02:00
|
|
|
|
|
|
|
# Player finished, redraw play buttons
|
2016-11-13 11:46:54 +01:00
|
|
|
if state.playproc_finished and bpy.context.screen != None:
|
2016-10-19 13:28:06 +02:00
|
|
|
state.playproc_finished = False
|
2016-11-23 15:34:59 +01:00
|
|
|
redraw_ui = True
|
2016-10-19 13:28:06 +02:00
|
|
|
|
|
|
|
# Compilation finished
|
2016-11-13 11:46:54 +01:00
|
|
|
if state.compileproc_finished and bpy.context.screen != None:
|
2016-10-19 13:28:06 +02:00
|
|
|
state.compileproc_finished = False
|
2016-11-23 15:34:59 +01:00
|
|
|
redraw_ui = True
|
2016-10-19 13:28:06 +02:00
|
|
|
# Compilation succesfull
|
|
|
|
if state.compileproc_success:
|
|
|
|
# Notify embedded player
|
2016-11-23 15:34:59 +01:00
|
|
|
if state.krom_running:
|
2016-10-19 13:28:06 +02:00
|
|
|
barmory.call_js('armory.Scene.patch();')
|
|
|
|
# Or switch to armory space
|
2017-03-15 12:30:14 +01:00
|
|
|
elif arm.utils.with_krom() and state.in_viewport:
|
2016-10-19 13:28:06 +02:00
|
|
|
state.play_area.type = 'VIEW_ARMORY'
|
|
|
|
# Prevent immediate operator patch
|
|
|
|
if len(ops) > 0:
|
|
|
|
last_operator = ops[-1]
|
|
|
|
|
2016-11-12 18:30:39 +01:00
|
|
|
# No attribute when using multiple windows?
|
2017-04-01 21:25:57 +02:00
|
|
|
if hasattr(bpy.context, 'active_object'):
|
|
|
|
obj = bpy.context.active_object
|
|
|
|
if obj != None:
|
|
|
|
if obj.is_updated_data: # + data.is_updated
|
|
|
|
recache(obj)
|
|
|
|
if obj.type == 'ARMATURE': # Newly parented objects needs to be recached
|
|
|
|
for c in obj.children:
|
|
|
|
if c.is_updated_data:
|
|
|
|
recache(c)
|
|
|
|
if hasattr(bpy.context, 'sculpt_object') and bpy.context.sculpt_object != None:
|
|
|
|
recache(bpy.context.sculpt_object)
|
|
|
|
if hasattr(bpy.context, 'active_pose_bone') and bpy.context.active_pose_bone != None:
|
|
|
|
recache(bpy.context.active_object)
|
2016-10-19 13:28:06 +02:00
|
|
|
|
2017-01-03 00:16:54 +01:00
|
|
|
if hasattr(bpy.context, 'object'):
|
|
|
|
obj = bpy.context.object
|
|
|
|
if obj != None:
|
|
|
|
if operators_changed:
|
2017-02-15 16:55:46 +01:00
|
|
|
op_changed(ops[-1], obj)
|
2017-01-03 00:16:54 +01:00
|
|
|
if obj.active_material != None and obj.active_material.is_updated:
|
2017-01-18 14:52:51 +01:00
|
|
|
if obj.active_material.lock_cache == True: # is_cached was set to true
|
|
|
|
obj.active_material.lock_cache = False
|
|
|
|
else:
|
|
|
|
obj.active_material.is_cached = False
|
2016-11-07 00:31:48 +01:00
|
|
|
|
2017-04-01 21:25:57 +02:00
|
|
|
def recache(edit_obj):
|
|
|
|
if edit_obj.type == 'MESH':
|
|
|
|
edit_obj.data.mesh_cached = False
|
|
|
|
elif edit_obj.type == 'ARMATURE':
|
|
|
|
edit_obj.data.data_cached = False
|
|
|
|
|
2017-02-15 16:55:46 +01:00
|
|
|
def op_changed(op, obj):
|
|
|
|
# Recache mesh data
|
|
|
|
if op.bl_idname == 'OBJECT_OT_modifier_add' or \
|
|
|
|
op.bl_idname == 'OBJECT_OT_modifier_remove' or \
|
|
|
|
op.bl_idname == 'OBJECT_OT_transform_apply' or \
|
|
|
|
op.bl_idname == 'OBJECT_OT_shade_smooth' or \
|
|
|
|
op.bl_idname == 'OBJECT_OT_shade_flat':
|
|
|
|
obj.data.mesh_cached = False
|
2017-02-09 22:52:47 +01:00
|
|
|
|
2017-03-06 02:29:03 +01:00
|
|
|
appended_py_paths = []
|
2016-10-31 19:29:03 +01:00
|
|
|
@persistent
|
|
|
|
def on_load_post(context):
|
2017-03-06 02:29:03 +01:00
|
|
|
global appended_py_paths
|
2017-04-01 21:25:57 +02:00
|
|
|
global first_update
|
|
|
|
|
|
|
|
first_update = True
|
2017-02-09 22:52:47 +01:00
|
|
|
|
2016-10-31 19:29:03 +01:00
|
|
|
props.init_properties_on_load()
|
2017-03-15 12:30:14 +01:00
|
|
|
make_renderer.reload_blend_data()
|
2016-10-31 19:29:03 +01:00
|
|
|
|
2017-03-06 02:29:03 +01:00
|
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
for lib in wrd.my_librarytraitlist:
|
|
|
|
if lib.enabled_prop:
|
2017-03-15 12:30:14 +01:00
|
|
|
fp = arm.utils.get_fp() + '/Libraries/' + lib.name
|
2017-03-06 02:29:03 +01:00
|
|
|
if fp not in appended_py_paths and os.path.exists(fp + '/blender.py'):
|
|
|
|
sys.path.append(fp)
|
|
|
|
appended_py_paths.append(fp)
|
|
|
|
import blender
|
|
|
|
blender.register()
|
2017-02-09 22:52:47 +01:00
|
|
|
|
2016-10-31 19:29:03 +01:00
|
|
|
@persistent
|
|
|
|
def on_save_pre(context):
|
|
|
|
props.init_properties_on_save()
|
2016-10-19 13:28:06 +02:00
|
|
|
|
|
|
|
def register():
|
|
|
|
bpy.app.handlers.scene_update_post.append(on_scene_update_post)
|
2016-10-31 19:29:03 +01:00
|
|
|
bpy.app.handlers.save_pre.append(on_save_pre)
|
|
|
|
bpy.app.handlers.load_post.append(on_load_post)
|
2017-01-13 15:09:23 +01:00
|
|
|
# On windows, on_load_post is not called when opening .blend file from explorer
|
2017-03-15 12:30:14 +01:00
|
|
|
if arm.utils.get_os() == 'win' and arm.utils.get_fp() != '':
|
2017-01-13 15:09:23 +01:00
|
|
|
on_load_post(None)
|
2016-10-19 13:28:06 +02:00
|
|
|
|
|
|
|
def unregister():
|
|
|
|
bpy.app.handlers.scene_update_post.remove(on_scene_update_post)
|
2016-10-31 19:29:03 +01:00
|
|
|
bpy.app.handlers.save_pre.remove(on_save_pre)
|
2017-01-13 15:11:30 +01:00
|
|
|
bpy.app.handlers.load_post.remove(on_load_post)
|