Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for changes in Blender 4.0 #648

Open
wants to merge 3 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions tools/armature.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,12 @@ def execute(self, context):
bpy.ops.mesh.reveal()

# Remove Bone Groups
for group in armature.pose.bone_groups:
armature.pose.bone_groups.remove(group)
# Replaced in 4.0 with Bone Collections (Armature.collections), which also subsumed Armature.layers. Bone colors
# are now defined per-bone, Bone.color.palette and PoseBone.color.palette
if Common.version_3_6_or_older:
bone_groups = armature.pose.bone_groups
for group in bone_groups:
bone_groups.remove(group)

# Bone constraints should be deleted
# if context.scene.remove_constraints:
Expand All @@ -506,13 +510,35 @@ def execute(self, context):

# Count steps for loading bar again and reset the layers
steps += len(armature.data.edit_bones)
if Common.version_3_6_or_older:
def set_bone_visible(edit_bone):
edit_bone.layers[0] = True
else:
# Armature/Bone layers were replaced with Bone Collections in Blender 4.0.
bone_collections = armature.data.collections
if not bone_collections:
# All bones are visible when there are no bone collections, so nothing to do.
def set_bone_visible(_edit_bone):
pass
else:
# The default collection on new Armatures is called "Bones" and usually has all bones assigned to it.
default_collection_name = "Bones"
bone_collection = bone_collections.get(default_collection_name)
if bone_collection is None:
# The default "Bones" collection does not exist, create it.
bone_collection = bone_collections.new(default_collection_name)
# Ensure the collection is visible.
bone_collection.is_visible = True

def set_bone_visible(edit_bone):
bone_collection.assign(edit_bone)
for bone in armature.data.edit_bones:
if bone.name in Bones.bone_list or bone.name.startswith(tuple(Bones.bone_list_with)):
if bone.parent is not None:
steps += 1
else:
steps -= 1
bone.layers[0] = True
set_bone_visible(bone)

# Start loading bar
current_step = 0
Expand Down
8 changes: 4 additions & 4 deletions tools/armature_manual.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def execute(self, context):
# active object e.g., the user has multiple armatures opened in pose mode, but a different armature is currently
# active. We can use an operator override to tell the operator to treat armature_obj as if it's the active
# object even if it's not, skipping the need to actually set armature_obj as the active object.
bpy.ops.pose.armature_apply({'active_object': armature_obj})
Common.op_override(bpy.ops.pose.armature_apply, {'active_object': armature_obj})

# Stop pose mode after operation
bpy.ops.cats_manual.stop_pose_mode()
Expand All @@ -411,14 +411,14 @@ def apply_armature_to_mesh_with_no_shape_keys(armature_obj, mesh_obj):
# first and potentially having unexpected results.
if bpy.app.version >= (2, 90, 0):
# modifier_move_to_index was added in Blender 2.90
bpy.ops.object.modifier_move_to_index(context_override, modifier=mod_name, index=0)
Common.op_override(bpy.ops.object.modifier_move_to_index, context_override, modifier=mod_name, index=0)
else:
# The newly created modifier will be at the bottom of the list
armature_mod_index = len(mesh_obj.modifiers) - 1
# Move the modifier up until it's at the top of the list
for _ in range(armature_mod_index):
bpy.ops.object.modifier_move_up(context_override, modifier=mod_name)
bpy.ops.object.modifier_apply(context_override, modifier=mod_name)
Common.op_override(bpy.ops.object.modifier_move_up, context_override, modifier=mod_name)
Common.op_override(bpy.ops.object.modifier_apply, context_override, modifier=mod_name)

@staticmethod
def apply_armature_to_mesh_with_shape_keys(armature_obj, mesh_obj, scene):
Expand Down
39 changes: 39 additions & 0 deletions tools/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from datetime import datetime
from html.parser import HTMLParser
from html.entities import name2codepoint
from typing import Optional, Set, Dict, Any

from . import common as Common
from . import supporter as Supporter
Expand Down Expand Up @@ -42,6 +43,9 @@ def version_2_93_or_older():
return bpy.app.version < (2, 90)


version_3_6_or_older = bpy.app.version < (4, 0)


def get_objects():
return bpy.context.scene.objects if version_2_79_or_older() else bpy.context.view_layer.objects

Expand Down Expand Up @@ -2473,6 +2477,41 @@ def wrapped_items_func(self, context):
return wrapped_items_func


if bpy.app.version >= (3, 2):
# Passing in context_override as a positional-only argument is deprecated as of Blender 3.2, replaced with
# Context.temp_override
def op_override(operator, context_override: dict[str, Any], context: Optional[bpy.types.Context] = None,
execution_context: Optional[str] = None,
undo: Optional[bool] = None, **operator_args) -> set[str]:
"""Call an operator with a context override"""
args = []
if execution_context is not None:
args.append(execution_context)
if undo is not None:
args.append(undo)

if context is None:
context = bpy.context
with context.temp_override(**context_override):
return operator(*args, **operator_args)
else:
def op_override(operator, context_override: Dict[str, Any], context: Optional[bpy.types.Context] = None,
execution_context: Optional[str] = None,
undo: Optional[bool] = None, **operator_args) -> Set[str]:
"""Call an operator with a context override"""
if context is not None:
context_base = context.copy()
context_base.update(context_override)
context_override = context_base
args = [context_override]
if execution_context is not None:
args.append(execution_context)
if undo is not None:
args.append(undo)

return operator(*args, **operator_args)


""" === THIS CODE COULD BE USEFUL === """

# def addvertex(meshname, shapekey_name):
Expand Down
Loading