rig_picker/operators/shape.py

235 lines
7.2 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 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)
for c in scn.rig_picker.canvas.users_collection:
c.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_options = {'REGISTER', 'UNDO'}
def execute(self,context):
scene = context.scene
rig = scene.rig_picker.rig
bone = rig.data.bones.active
if bone:
context.object.name = bone.name
context.object.rig_picker.name = bone.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):
scn = context.scene
ob = context.object
collection = get_picker_collection(ob)
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.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
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)