266 lines
7.9 KiB
Python
266 lines
7.9 KiB
Python
import json
|
|
from os.path import abspath
|
|
from pathlib import Path
|
|
import bpy
|
|
from bpy.types import Operator
|
|
from bpy.props import IntProperty
|
|
from mathutils import Matrix
|
|
|
|
from ..core.shape import get_picker_data
|
|
from ..core.addon_utils import is_shape, get_picker_collection
|
|
from ..core.bl_utils import link_mat_to_object, flip_name
|
|
|
|
|
|
class RP_OT_create_shape(Operator):
|
|
bl_label = "Create UI shape"
|
|
bl_idname = "rigpicker.create_shape"
|
|
# bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.object and context.object.mode == "POSE"
|
|
|
|
def invoke(self, context, event):
|
|
return context.window_manager.invoke_props_dialog(self)
|
|
|
|
def draw(self, context):
|
|
for col in bpy.data.collections:
|
|
if col.rig_picker.enabled:
|
|
self.layout.prop(col.rig_picker, "link_shape", text=col.name)
|
|
|
|
def execute(self, context):
|
|
scn = context.scene
|
|
vl = context.view_layer
|
|
|
|
offset = 0
|
|
for bone in context.selected_pose_bones:
|
|
name = bone.name
|
|
|
|
mesh = bpy.data.meshes.new(name)
|
|
ob = bpy.data.objects.new(name, mesh)
|
|
|
|
ob.rig_picker.name = name
|
|
|
|
verts = [(0, 0, 0)]
|
|
edges = []
|
|
faces = []
|
|
|
|
mesh.from_pydata(verts, edges, faces)
|
|
|
|
picker_selected_cols = [
|
|
col for col in bpy.data.collections if col.rig_picker.link_shape
|
|
]
|
|
|
|
for col in picker_selected_cols or [scn.collection]:
|
|
col.objects.link(ob)
|
|
|
|
ob.location.z = 0.05
|
|
ob.location.x = offset
|
|
|
|
for obj in scn.objects:
|
|
obj.select_set(False)
|
|
|
|
vl.objects.active = ob
|
|
ob.select_set(True)
|
|
|
|
offset += 0.05
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class RP_OT_name_from_bone(Operator):
|
|
bl_label = "Name Shape from selected bones"
|
|
bl_idname = "rigpicker.name_from_bone"
|
|
bl_description = "Rename all shapes from related bones name"
|
|
# bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
|
|
col = get_picker_collection(context.object)
|
|
|
|
for ob in col.all_objects:
|
|
if ob.rig_picker.shape_type == "BONE":
|
|
ob.name = ob.rig_picker.name
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class RP_OT_mirror_shape(Operator):
|
|
bl_label = "Mirror UI shape"
|
|
bl_idname = "rigpicker.mirror_shape"
|
|
# bl_options = g
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.object and context.object.type in ("MESH", "CURVE", "TEXT")
|
|
|
|
def execute(self, context):
|
|
collection = get_picker_collection(context.object)
|
|
objects = context.selected_objects
|
|
|
|
# Remove mirror object:
|
|
for ob in list(collection.all_objects):
|
|
if ob in objects:
|
|
continue
|
|
|
|
for mod in ob.modifiers:
|
|
if (
|
|
mod.type == "NODES"
|
|
and mod.node_group
|
|
and mod.node_group.name == "Symmetrize"
|
|
and mod.get("Socket_2") in objects
|
|
):
|
|
|
|
bpy.data.objects.remove(ob)
|
|
|
|
if collection.rig_picker.symmetry:
|
|
x_axis = collection.rig_picker.symmetry.matrix_world.to_translation()[0]
|
|
else:
|
|
x_axis = 0
|
|
|
|
for ob in objects:
|
|
flipped_name = flip_name(ob.name)
|
|
if flipped_name == ob.name:
|
|
suffix = ".L"
|
|
flipped_suffix = ".R"
|
|
# Determine side of the object
|
|
if ob.matrix_world.to_translation()[0] < x_axis:
|
|
suffix, flipped_suffix = flipped_suffix, suffix
|
|
|
|
flipped_name = f"{ob.name}{flipped_suffix}"
|
|
ob.name = f"{ob.name}{suffix}"
|
|
|
|
flipped_object = ob.copy()
|
|
flipped_object.name = flipped_name
|
|
flipped_object.parent = None
|
|
flipped_object.matrix_world = Matrix()
|
|
for mod in list(flipped_object.modifiers):
|
|
flipped_object.modifiers.remove(mod)
|
|
|
|
# Add symmetrize modifier TODO add it into a resource
|
|
mod = flipped_object.modifiers.new(name="Symmetrize", type="NODES")
|
|
mod.node_group = bpy.data.node_groups["Symmetrize"]
|
|
mod["Socket_2"] = ob
|
|
mod["Socket_3"] = collection.rig_picker.symmetry
|
|
|
|
for col in ob.users_collection:
|
|
col.objects.link(flipped_object)
|
|
|
|
if ob.rig_picker.shape_type == "BONE":
|
|
flipped_object.rig_picker.name = flip_name(ob.rig_picker.name)
|
|
|
|
elif ob.rig_picker.shape_type == "FUNCTION":
|
|
args = {}
|
|
for key, value in eval(ob.rig_picker.arguments).items():
|
|
if type(value) == list:
|
|
mirrored_value = []
|
|
for item in value:
|
|
mirrored_value.append(flip_name(item))
|
|
|
|
elif type(value) == str:
|
|
mirrored_value = flip_name(value)
|
|
args[key] = mirrored_value
|
|
|
|
flipped_object.rig_picker.arguments = str(args)
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class RP_OT_select_shape_type(Operator):
|
|
bl_label = "Select Shape by Type"
|
|
bl_idname = "rigpicker.select_shape_type"
|
|
# bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
shape_type = bpy.props.EnumProperty(
|
|
items=[(i.upper(), i, "") for i in ("Bone", "Display", "Function")]
|
|
)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
col = layout.column()
|
|
col.prop(self, "shape_type", expand=True)
|
|
|
|
def execute(self, context):
|
|
scene = context.scene
|
|
# print(self.shape_type)
|
|
canvas = context.scene.rig_picker.canvas
|
|
if canvas:
|
|
for ob in [o for o in bpy.data.objects if o.layers == canvas.layers]:
|
|
if (
|
|
ob.type in ["MESH", "CURVE", "FONT"]
|
|
and ob.rig_picker.shape_type == self.shape_type
|
|
):
|
|
ob.select = True
|
|
|
|
return {"FINISHED"}
|
|
|
|
def invoke(self, context, event):
|
|
wm = context.window_manager
|
|
return wm.invoke_props_dialog(self, width=150)
|
|
|
|
|
|
class RP_OT_save_picker(Operator):
|
|
bl_label = "Store UI Data"
|
|
bl_idname = "rigpicker.save_picker"
|
|
|
|
index: IntProperty(default=-1)
|
|
|
|
def execute(self, context):
|
|
scn = context.scene
|
|
ob = context.object
|
|
|
|
if self.index == -1:
|
|
collection = get_picker_collection(ob)
|
|
else:
|
|
source = context.active_object.data.rig_picker.sources[self.index].source
|
|
source = Path(bpy.path.abspath(source, library=ob.data.library)).resolve()
|
|
collection = next(
|
|
(
|
|
c
|
|
for c in set(scn.collection.children_recursive)
|
|
if c.rig_picker.enabled
|
|
and Path(bpy.path.abspath(c.rig_picker.destination)).resolve()
|
|
== source
|
|
),
|
|
None,
|
|
)
|
|
|
|
if not collection:
|
|
self.report({"ERROR"}, "No Picker found")
|
|
return {"CANCELLED"}
|
|
|
|
canvas = collection.rig_picker.canvas
|
|
# rig = collection.rig_picker.rig
|
|
shapes = [
|
|
o
|
|
for o in collection.all_objects
|
|
if o != canvas and o.type in ("MESH", "CURVE", "FONT")
|
|
]
|
|
|
|
if not canvas:
|
|
self.report({"ERROR"}, "Choose a Canvas")
|
|
return {"CANCELLED"}
|
|
|
|
picker_data = get_picker_data(collection)
|
|
|
|
picker_path = Path(bpy.path.abspath(collection.rig_picker.destination))
|
|
|
|
print(f"Save Picker to {picker_path}")
|
|
picker_path.write_text(json.dumps(picker_data))
|
|
|
|
bpy.ops.rigpicker.reload_picker()
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
classes = (
|
|
RP_OT_create_shape,
|
|
RP_OT_name_from_bone,
|
|
RP_OT_mirror_shape,
|
|
RP_OT_select_shape_type,
|
|
RP_OT_save_picker,
|
|
)
|
|
|
|
register, unregister = bpy.utils.register_classes_factory(classes)
|