Add menu and some cleanup

This commit is contained in:
ChristopheSeux
2024-02-26 11:26:49 +01:00
parent 917531f59a
commit 150bae5920
13 changed files with 778 additions and 571 deletions
+18 -1
View File
@@ -1,6 +1,21 @@
import bpy
from .bl_utils import get_mat
from .bl_utils import get_mat, get_collection_parents
def get_picker_collection(ob=None):
"""Return the picker collection of an object"""
if not ob:
ob = bpy.context.object
for col in ob.users_collection:
if col.rig_picker.enabled:
return col
if picker_col := next((c for c in get_collection_parents(col) if c.rig_picker.enabled), None):
return picker_col
def is_shape(ob):
scn = bpy.context.scene
@@ -15,6 +30,7 @@ def is_shape(ob):
return False
def get_object_color(ob):
if not ob.data.materials:
return
@@ -29,6 +45,7 @@ def get_object_color(ob):
return emit_node.inputs['Color'].default_value
def get_operator_from_id(idname):
if not '.' in idname:
return
+47
View File
@@ -2,6 +2,34 @@
import bpy
def get_collection_parents(col, root=None, cols=None):
"""Return all direct collection parents
Args:
col (bpy.types.Collection): collection to get parents from
root (bpy.types.Collection, optional): collection to search in (recursive) instead of the scene collection.
Defaults to None.
cols (_type_, optional): for recursivity, store the parent collections.
Defaults to None.
Returns:
list[bpy.types.Collection]: a list of direct parents
"""
if cols is None:
cols = []
if root is None:
root = bpy.context.scene.collection
for sub in root.children:
if sub == col:
cols.append(root)
if len(sub.children):
cols = get_collection_parents(col, root=sub, cols=cols)
return cols
def get_view_3d_override():
windows = bpy.context.window_manager.windows
areas = [a for w in windows for a in w.screen.areas if a.type == 'VIEW_3D']
@@ -31,6 +59,12 @@ def link_mat_to_object(ob):
sl.link = 'OBJECT'
sl.material = m
def eval_attr(ob, name):
resolved = ob
for o in name.split("."):
resolved = getattr(resolved, o)
return resolved
def flip_name(name):
if not name:
return
@@ -41,6 +75,19 @@ def flip_name(name):
else:
return bpy.utils.flip_name(name)
def split_path(path) :
try :
bone_name = path.split('["')[1].split('"]')[0]
except Exception:
bone_name = None
try :
prop_name = path.split('["')[2].split('"]')[0]
except Exception:
prop_name = None
return bone_name, prop_name
def hide_layers(args):
""" """
ob = bpy.context.object
+42 -19
View File
@@ -232,7 +232,7 @@ class BoneShape(Shape):
if self.hide:
return self.draw_hided()
elif self.bone.custom_shape_scale_xyz.length < 0.00001:
elif self.bone and self.bone.custom_shape_scale_xyz.length < 0.00001:
return self.draw_zero_scaled()
# Draw Fill
@@ -258,8 +258,9 @@ class BoneShape(Shape):
def assign_bone_event(self):
#print('assign_bone_event', self)
scn = bpy.context.scene
rig = scn.rig_picker.rig
rig = self.picker.rig
source_object = scn.objects.get(self.source_name)
if not source_object:
print(f'Source object {self.source_name} not found')
@@ -270,6 +271,9 @@ class BoneShape(Shape):
print('You need to have an active bone')
return
#print(active_bone, source_object)
#print(rig)
source_object.name = rig.data.bones.active.name
source_object.rig_picker.name = rig.data.bones.active.name
def release_event(self, mode='SET'):
@@ -452,10 +456,10 @@ class Picker:
def assign_bone_event(self):
for shape in self.shapes:
if shape.type=='bone' and shape.hover:
if shape.type == 'bone' and shape.hover:
shape.assign_bone_event()
bpy.ops.rigpicker.save_picker(index=self.index)
bpy.ops._rigpicker.save_picker(index=self.index)
def press_event(self, mode='SET'):
for shape in self.shapes:
@@ -626,11 +630,11 @@ class PickerGroup:
if self.timer:
self.timer.cancel()
self.timer = threading.Timer(0.5, self.tooltip_event)
self.timer = threading.Timer(0.4, self.tooltip_event)
self.timer.start()
def press_event(self, mode='SET'):
self.clear_tooltip()
#self.clear_tooltip()
for picker in self.pickers:
if picker.under_mouse(self.location):
@@ -678,7 +682,7 @@ class PickerGroup:
#print(self.hover_shape, self.hover_shape.type)
if self.hover_shape and self.hover_shape.type != 'display':
if self.hover_shape.type == 'bone':
if self.hover_shape.type == 'bone' and self.hover_shape.bone:
self.tooltip = self.hover_shape.bone.name
else:
self.tooltip = self.hover_shape.tooltip
@@ -706,28 +710,47 @@ class PickerGroup:
return center
def get_picker_path(rig, start=None):
picker_path = rig.data.get('rig_picker', {}).get('source')
if not picker_path:
return
def load_picker_data(rig):
if 'pickers' in rig.data.rig_picker:
picker_datas = [p.to_dict() for p in rig.rig_picker['pickers']]
else:
picker_datas = []
picker_path = bpy.path.abspath(picker_path, library=rig.data.library, start=start)
for picker in rig.data.rig_picker.sources:
picker_path = Path(bpy.path.abspath(picker.source, library=rig.data.library))
if not picker_path.exists():
print(f'Picker path not exists: {picker_path.resolve()}')
continue
print('Load picker from', picker_path.resolve())
picker_data = json.loads(picker_path.read_text(encoding='utf-8'))
picker_datas.append(picker_data)
PICKERS[rig] = PickerGroup(rig, picker_datas)
def get_picker_path(rig, source, start=None):
picker_path = bpy.path.abspath(source, library=rig.data.library, start=start)
return Path(os.path.abspath(picker_path))
def pack_picker(rig, start=None):
picker_path = get_picker_path(rig, start=start)
if picker_path and picker_path.exists():
if 'rig_picker' not in rig.data.keys():
rig.data['rig_picker'] = {}
pickers = []
for picker_source in rig.data.get('rig_picker', {}).get('sources', {}):
picker_path = get_picker_path(rig, picker_source['source'], start)
if not picker_path.exists():
print(f'{picker_path} not exists')
continue
picker_data = json.loads(picker_path.read_text(encoding='utf-8'))
pickers.append(picker_data)
rig.data['rig_picker']['picker'] = json.loads(picker_path.read_text(encoding='utf-8'))
rig.data['rig_picker']['pickers'] = pickers
def unpack_picker(rig):
if 'rig_picker' not in rig.data.keys():
return
if 'picker' in rig.data['rig_picker'].keys():
del rig.data['rig_picker']['picker']
if 'pickers' in rig.data['rig_picker'].keys():
del rig.data['rig_picker']['pickers']
+97 -77
View File
@@ -61,99 +61,119 @@ def contour_loops(bm, vert_index=0, loops=None, vert_indices=None):
return loops
def get_picker_data(objects, canvas, rig):
picker_datas = []
gamma = 1 / 2.2
if canvas.type =='CURVE':
def get_shape_data(ob, matrix=None, depsgraph=None):
if not matrix:
matrix = Matrix()
if not depsgraph:
depsgraph = bpy.context.evaluated_depsgraph_get()
gamma = 1 / 2.2
eval_ob = ob.evaluated_get(depsgraph)
mesh = eval_ob.to_mesh()
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.002)
bmesh.ops.dissolve_limit(bm, angle_limit=0.001745, verts=bm.verts, edges=bm.edges)
bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
bmesh.ops.triangulate(bm, faces=bm.faces)
edges = [[v.index for v in e.verts] for e in bm.edges if len(e.link_faces)<=1]
bm.to_mesh(mesh)
mesh.update()
bm.clear()
points = []
polygons = []
depths = []
for vert in mesh.vertices:
co = matrix @ (ob.matrix_world @ Vector(vert.co))
points.append([round(co[0]), round(co[1])])
depths += [co[2]]
if depths:
depth = max(depths)
else:
print(f'{ob.name} has no vertices')
depth = 0
for face in mesh.polygons:
polygons.append([v for v in face.vertices])
color = get_object_color(ob)
if color:
color = [round(pow(c, gamma), 4) for c in color]
else:
color = [0.5, 0.5, 0.5]
shape = {
'source_name': ob.name,
'tooltip': ob.rig_picker.name,
'depth': depth,
'points': points,
'polygons': polygons,
'edges': edges,
'color': color,
'type': ob.rig_picker.shape_type
}
if shape['type'] =='OPERATOR':
shape['operator'] = ob.rig_picker.operator
shape['shortcut'] = ob.rig_picker.shortcut
elif shape['type'] =='BONE':
shape['bone'] = ob.rig_picker.name
eval_ob.to_mesh_clear()
return shape
def get_picker_data(collection):
picker_data = []
depsgraph = bpy.context.evaluated_depsgraph_get()
canvas = collection.rig_picker.canvas
if canvas.type == 'CURVE':
canvas_points = canvas.data.splines[0].points
else:
canvas_points = canvas.data.vertices
canvas_coords = [canvas.matrix_world@Vector((p.co)) for p in canvas_points]
height = max(canvas_coords).y - min(canvas_coords).y
width = max(canvas_coords).x - min(canvas_coords).x
height = abs(max(canvas_coords).y - min(canvas_coords).y)
width = abs(max(canvas_coords).x - min(canvas_coords).x)
canvas_center = sum(canvas_coords, Vector()) / len(canvas_coords)
canvas_scale_fac = 4096 / max(height, width)# Reference height for the canvas
center = sum(canvas_coords, Vector()) / len(canvas_coords)
scale = 2048 / max(height, width)# Reference height for the canvas
objects.append(canvas)
dg = bpy.context.evaluated_depsgraph_get()
matrix = Matrix.Translation(-center)
matrix = Matrix.Scale(scale, 4) @ matrix
#sorted by their z axes
for ob in sorted(objects, key=lambda x: bound_box_center(x)[2]):
for ob in collection.all_objects:
if ob.instance_collection:
for shape in ob.instance_collection.all_objects:
picker_data.append(get_shape_data(shape, matrix=matrix@ob.matrix_world, depsgraph=depsgraph))
elif ob.type in ('MESH', 'CURVE', 'FONT'):
picker_data.append(get_shape_data(ob, matrix=matrix, depsgraph=depsgraph))
print('Storing shape', ob.name)
mesh = bpy.data.meshes.new_from_object(ob.evaluated_get(dg))
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.002)
bmesh.ops.dissolve_limit(bm, angle_limit=0.001745, verts=bm.verts, edges=bm.edges)
bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
bmesh.ops.triangulate(bm, faces=bm.faces)
#bm_loops = contour_loops(bm)
#loops = [[l.index for l in loop] for loop in bm_loops]
loops = []
edges = [[v.index for v in e.verts] for e in bm.edges if len(e.link_faces)<=1]
bm.to_mesh(mesh)
mesh.update()
bm.clear()
points = []
#edges = []
polygons = []
for p in mesh.vertices:
point = ob.matrix_world@Vector((p.co))
point = (point - canvas_center) * canvas_scale_fac
points.append([round(point[0]), round(point[1])])
for f in mesh.polygons:
polygons.append([v for v in f.vertices])
#for e in mesh.edges:
#
# edges.append([v for v in e.vertices])
color = get_object_color(ob)
if color:
color = [round(pow(c, gamma), 4) for c in color]
else:
color = [0.5, 0.5, 0.5]
shape = {
'source_name': ob.name,
'tooltip': ob.rig_picker.name,
'points': points,
'polygons': polygons,
'edges': edges,
'loops': loops,
'color': color,
'type': 'CANVAS' if ob == canvas else ob.rig_picker.shape_type
}
if shape['type'] =='OPERATOR':
shape['operator'] = ob.rig_picker.operator
#if ob.rig_picker.arguments:
#shape['arguments'] = ob.rig_picker.arguments
#if ob.rig_picker.shortcut:
shape['shortcut'] = ob.rig_picker.shortcut
elif shape['type'] =='BONE':
shape['bone'] = ob.rig_picker.name
picker_datas.append(shape)
#print(f'{ob.name} of type {ob.type} not supported')
continue
picker_data.sort(key=lambda x : x['depth'])
#print(picker_datas)
return picker_datas
return picker_data
#rig.data.rig_picker['shapes'] = picker_datas