141 lines
4.9 KiB
Python
141 lines
4.9 KiB
Python
import bpy
|
|
from bpy.types import Object
|
|
from .utils import get_addon_prefs
|
|
|
|
mode_history = []
|
|
suspend_hook = False
|
|
|
|
def on_weight_paint_enter():
|
|
context = bpy.context
|
|
obj = context.active_object
|
|
wm = context.window_manager
|
|
|
|
viewports = []
|
|
for window in wm.windows:
|
|
for area in window.workspace.screens[0].areas:
|
|
if area.spaces.active and area.spaces.active.type == 'VIEW_3D':
|
|
viewports.append(area.spaces.active)
|
|
|
|
prefs = get_addon_prefs(context)
|
|
tool_settings = context.scene.tool_settings
|
|
if prefs.always_show_zero_weights:
|
|
tool_settings.vertex_group_user = 'ACTIVE'
|
|
if prefs.always_auto_normalize:
|
|
tool_settings.use_auto_normalize = True
|
|
if prefs.always_multipaint:
|
|
tool_settings.use_multipaint = True
|
|
|
|
# Store old visibility settings in a Custom Property in the WindowManager.
|
|
if 'weight_paint_toggle' not in wm:
|
|
wm['weight_paint_toggle'] = {}
|
|
|
|
wp_toggle = wm['weight_paint_toggle']
|
|
|
|
# ENSURING ARMATURE VISIBILITY
|
|
armature = get_armature_of_meshob(obj)
|
|
if not armature:
|
|
return
|
|
print("Entering WP mode: ", context.active_object.name, armature.name)
|
|
# Save all object visibility related info so it can be restored later.
|
|
wp_toggle['arm_disabled'] = armature.hide_viewport
|
|
wp_toggle['arm_hide'] = armature.hide_get()
|
|
wp_toggle['arm_coll_assigned'] = False
|
|
armature.hide_viewport = False
|
|
armature.hide_set(False)
|
|
|
|
for viewport in viewports:
|
|
if viewport.local_view:
|
|
wp_toggle['arm_local_view'] = armature.local_view_get(viewport)
|
|
armature.local_view_set(viewport, True)
|
|
if prefs.always_xray:
|
|
wp_toggle['bone_xray'] = viewport.overlay.show_xray_bone
|
|
viewport.overlay.show_xray_bone = True
|
|
|
|
# If the armature is still not visible, add it to the scene root collection.
|
|
if not armature.visible_get() and not armature.name in context.scene.collection.objects:
|
|
context.scene.collection.objects.link(armature)
|
|
wp_toggle['arm_coll_assigned'] = True
|
|
|
|
if armature.visible_get():
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
context.view_layer.objects.active = armature
|
|
armature.select_set(True)
|
|
context.view_layer.objects.active = obj
|
|
bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
|
|
|
|
return armature.visible_get()
|
|
|
|
|
|
def on_weight_paint_leave():
|
|
context = bpy.context
|
|
obj = context.active_object
|
|
wm = context.window_manager
|
|
|
|
viewports = []
|
|
for window in wm.windows:
|
|
for area in window.workspace.screens[0].areas:
|
|
if area.spaces.active and area.spaces.active.type == 'VIEW_3D':
|
|
viewports.append(area.spaces.active)
|
|
|
|
if 'weight_paint_toggle' not in wm:
|
|
# There is no saved data to restore from, nothing else to do.
|
|
return
|
|
|
|
wp_toggle = wm['weight_paint_toggle']
|
|
wp_toggle_as_dict = wp_toggle.to_dict()
|
|
|
|
# Reset the stored data
|
|
wm['weight_paint_toggle'] = {}
|
|
|
|
armature = get_armature_of_meshob(obj)
|
|
if not armature:
|
|
return
|
|
|
|
if armature.visible_get():
|
|
context.view_layer.objects.active = armature
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
context.view_layer.objects.active = obj
|
|
|
|
# If an armature was un-hidden, hide it again.
|
|
armature.hide_viewport = wp_toggle_as_dict['arm_disabled']
|
|
armature.hide_set(wp_toggle_as_dict['arm_hide'])
|
|
|
|
# Restore whether the armature is in local view or not.
|
|
for viewport in viewports:
|
|
if 'arm_local_view' in wp_toggle_as_dict and viewport.local_view:
|
|
armature.local_view_set(viewport, wp_toggle_as_dict['arm_local_view'])
|
|
if 'bone_xray' in wp_toggle_as_dict:
|
|
viewport.overlay.show_xray_bone = wp_toggle_as_dict['bone_xray']
|
|
|
|
# Remove armature from scene root collection if it was moved there.
|
|
if wp_toggle_as_dict['arm_coll_assigned']:
|
|
context.scene.collection.objects.unlink(armature)
|
|
|
|
|
|
def get_armature_of_meshob(obj: Object):
|
|
"""Find and return the armature that deforms this mesh object."""
|
|
for mod in obj.modifiers:
|
|
if mod.type == 'ARMATURE':
|
|
return mod.object
|
|
|
|
@bpy.app.handlers.persistent
|
|
def detect_mode_switch(scene=None, depsgraph=None):
|
|
global suspend_hook
|
|
if suspend_hook:
|
|
return
|
|
context = bpy.context
|
|
mode_history.append(context.mode)
|
|
if mode_history[-1] == 'PAINT_WEIGHT' and (len(mode_history)==1 or mode_history[-2] != 'PAINT_WEIGHT'):
|
|
suspend_hook = True
|
|
on_weight_paint_enter()
|
|
suspend_hook = False
|
|
elif len(mode_history) > 1 and mode_history[-2] == 'PAINT_WEIGHT' and mode_history[-1] != 'PAINT_WEIGHT':
|
|
suspend_hook = True
|
|
on_weight_paint_leave()
|
|
suspend_hook = False
|
|
|
|
def register():
|
|
bpy.app.handlers.depsgraph_update_post.append(detect_mode_switch)
|
|
|
|
def unregister():
|
|
bpy.app.handlers.depsgraph_update_post.remove(detect_mode_switch) |