Compare commits
6 Commits
master
...
black-form
| Author | SHA1 | Date | |
|---|---|---|---|
| d90fccb014 | |||
| d09119f9d7 | |||
| 465a22d5a9 | |||
| cc60a25aca | |||
| 355e7b23cf | |||
| 622048d573 |
1
.git-blame-ignore-revs
Normal file
1
.git-blame-ignore-revs
Normal file
@ -0,0 +1 @@
|
|||||||
|
622048d573ad87c5be84f65e64a7a3290c9305d1
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
14
__init__.py
14
__init__.py
@ -8,18 +8,12 @@ bl_info = {
|
|||||||
"warning": "",
|
"warning": "",
|
||||||
"wiki_url": "",
|
"wiki_url": "",
|
||||||
"tracker_url": "",
|
"tracker_url": "",
|
||||||
"category": "Rigging"}
|
"category": "Rigging",
|
||||||
|
}
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
modules = (
|
modules = (".operators", ".properties", ".ui", ".area", ".gizmo", ".draw_handlers")
|
||||||
'.operators',
|
|
||||||
'.properties',
|
|
||||||
'.ui',
|
|
||||||
'.area',
|
|
||||||
'.gizmo',
|
|
||||||
'.draw_handlers'
|
|
||||||
)
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
@ -29,6 +23,7 @@ if "bpy" in locals():
|
|||||||
module = importlib.import_module(name, __name__)
|
module = importlib.import_module(name, __name__)
|
||||||
importlib.reload(module)
|
importlib.reload(module)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
if bpy.app.background:
|
if bpy.app.background:
|
||||||
return
|
return
|
||||||
@ -36,6 +31,7 @@ def register():
|
|||||||
module = importlib.import_module(name, __name__)
|
module = importlib.import_module(name, __name__)
|
||||||
module.register()
|
module.register()
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
if bpy.app.background:
|
if bpy.app.background:
|
||||||
return
|
return
|
||||||
|
|||||||
102
area.py
102
area.py
@ -6,34 +6,35 @@ from .constants import PICKERS
|
|||||||
# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
|
# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
|
||||||
class RigPickerTree(NodeTree):
|
class RigPickerTree(NodeTree):
|
||||||
# Description string
|
# Description string
|
||||||
'''A custom node tree type that will show up in the editor type list'''
|
"""A custom node tree type that will show up in the editor type list"""
|
||||||
# Optional identifier string. If not explicitly defined, the python class name is used.
|
# Optional identifier string. If not explicitly defined, the python class name is used.
|
||||||
# Label for nice name display
|
# Label for nice name display
|
||||||
bl_label = "Rig Picker"
|
bl_label = "Rig Picker"
|
||||||
# Icon identifier
|
# Icon identifier
|
||||||
bl_icon = 'OUTLINER_DATA_ARMATURE'
|
bl_icon = "OUTLINER_DATA_ARMATURE"
|
||||||
|
|
||||||
|
|
||||||
class RP_MT_picker(Menu):
|
class RP_MT_picker(Menu):
|
||||||
"""Picker"""
|
"""Picker"""
|
||||||
|
|
||||||
bl_label = "Picker"
|
bl_label = "Picker"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
scn = context.scene
|
scn = context.scene
|
||||||
|
|
||||||
|
layout.operator("rigpicker.reload_picker", icon="FILE_REFRESH")
|
||||||
layout.operator('rigpicker.reload_picker', icon='FILE_REFRESH')
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|
||||||
# Has at least one picker collection in the scene
|
# Has at least one picker collection in the scene
|
||||||
if not [c.rig_picker.enabled for c in scn.collection.children_recursive]:
|
if not [c.rig_picker.enabled for c in scn.collection.children_recursive]:
|
||||||
row.enabled = False
|
row.enabled = False
|
||||||
row.prop(scn.rig_picker, 'use_pick_bone', text='Auto Bone Assign')
|
row.prop(scn.rig_picker, "use_pick_bone", text="Auto Bone Assign")
|
||||||
|
|
||||||
|
|
||||||
class RP_MT_animation(Menu):
|
class RP_MT_animation(Menu):
|
||||||
"""Picker"""
|
"""Picker"""
|
||||||
|
|
||||||
bl_label = "Animation"
|
bl_label = "Animation"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
@ -47,51 +48,62 @@ class RP_MT_animation(Menu):
|
|||||||
row.enabled = False
|
row.enabled = False
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
op = layout.operator("rigpicker.call_operator", text='Select All')
|
op = layout.operator("rigpicker.call_operator", text="Select All")
|
||||||
op.operator = "pose.select_all"
|
op.operator = "pose.select_all"
|
||||||
op.arguments = '{"action": "SELECT"}'
|
op.arguments = '{"action": "SELECT"}'
|
||||||
|
|
||||||
op = layout.operator("rigpicker.call_operator", text='Select All')
|
op = layout.operator("rigpicker.call_operator", text="Select All")
|
||||||
op.operator = "pose.select_all"
|
op.operator = "pose.select_all"
|
||||||
op.arguments = '{"action": "DESELECT"}'
|
op.arguments = '{"action": "DESELECT"}'
|
||||||
|
|
||||||
op = layout.operator("rigpicker.call_operator", text='Frame Selected')
|
op = layout.operator("rigpicker.call_operator", text="Frame Selected")
|
||||||
op.operator = "view3d.view_selected"
|
op.operator = "view3d.view_selected"
|
||||||
op.view_3d = True
|
op.view_3d = True
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.operator("rigpicker.call_operator", text='Insert Keyframe').operator="animtoolbox.insert_keyframe"
|
layout.operator("rigpicker.call_operator", text="Insert Keyframe").operator = (
|
||||||
layout.operator("anim.keyframe_delete_v3d", text='Delete Keyframe')
|
"animtoolbox.insert_keyframe"
|
||||||
|
)
|
||||||
|
layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframe")
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
op = layout.operator("rigpicker.call_operator", text='Move')
|
op = layout.operator("rigpicker.call_operator", text="Move")
|
||||||
op.operator="transform.translate"
|
op.operator = "transform.translate"
|
||||||
op.invoke = True
|
op.invoke = True
|
||||||
op.view_3d = True
|
op.view_3d = True
|
||||||
|
|
||||||
layout.operator("node.picker_transform", text='Rotate').mode='ROTATE'
|
layout.operator("node.picker_transform", text="Rotate").mode = "ROTATE"
|
||||||
layout.operator("node.picker_transform", text='Scale').mode='SCALE'
|
layout.operator("node.picker_transform", text="Scale").mode = "SCALE"
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.operator("rigpicker.call_operator", text='Reset Bone').operator="animtoolbox.reset_bone"
|
layout.operator("rigpicker.call_operator", text="Reset Bone").operator = (
|
||||||
layout.operator("rigpicker.call_operator", text='Clear Location').operator='pose.loc_clear'
|
"animtoolbox.reset_bone"
|
||||||
layout.operator("rigpicker.call_operator", text='Clear Rotation').operator='pose.rot_clear'
|
)
|
||||||
layout.operator("rigpicker.call_operator", text='Clear Scale').operator='pose.scale_clear'
|
layout.operator("rigpicker.call_operator", text="Clear Location").operator = (
|
||||||
|
"pose.loc_clear"
|
||||||
|
)
|
||||||
|
layout.operator("rigpicker.call_operator", text="Clear Rotation").operator = (
|
||||||
|
"pose.rot_clear"
|
||||||
|
)
|
||||||
|
layout.operator("rigpicker.call_operator", text="Clear Scale").operator = (
|
||||||
|
"pose.scale_clear"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def draw_header(self, context):
|
def draw_header(self, context):
|
||||||
if not context.space_data.tree_type == 'RigPickerTree':
|
if not context.space_data.tree_type == "RigPickerTree":
|
||||||
self._draw(context)
|
self._draw(context)
|
||||||
return
|
return
|
||||||
|
|
||||||
scn = context.scene
|
scn = context.scene
|
||||||
|
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.template_header()
|
layout.template_header()
|
||||||
|
|
||||||
if not context.space_data.node_tree:
|
if not context.space_data.node_tree:
|
||||||
ntree = bpy.data.node_groups.get('.rig_picker')
|
ntree = bpy.data.node_groups.get(".rig_picker")
|
||||||
if not ntree:
|
if not ntree:
|
||||||
ntree = bpy.data.node_groups.new('.rig_picker', 'RigPickerTree')
|
ntree = bpy.data.node_groups.new(".rig_picker", "RigPickerTree")
|
||||||
|
|
||||||
context.space_data.node_tree = ntree
|
context.space_data.node_tree = ntree
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
@ -99,17 +111,19 @@ def draw_header(self, context):
|
|||||||
row.menu("RP_MT_animation")
|
row.menu("RP_MT_animation")
|
||||||
|
|
||||||
ob = context.object
|
ob = context.object
|
||||||
if not ob or not ob.type == 'ARMATURE':
|
if not ob or not ob.type == "ARMATURE":
|
||||||
return
|
return
|
||||||
|
|
||||||
picker_group = PICKERS.get(ob)
|
picker_group = PICKERS.get(ob)
|
||||||
if not picker_group:
|
if not picker_group:
|
||||||
return
|
return
|
||||||
|
|
||||||
if scn.rig_picker.use_pick_bone:
|
if scn.rig_picker.use_pick_bone:
|
||||||
layout.alert = True
|
layout.alert = True
|
||||||
layout.label(text='Auto Bone Assign')
|
layout.label(text="Auto Bone Assign")
|
||||||
layout.prop(scn.rig_picker, 'use_pick_bone', icon='PANEL_CLOSE', text='', emboss=False)
|
layout.prop(
|
||||||
|
scn.rig_picker, "use_pick_bone", icon="PANEL_CLOSE", text="", emboss=False
|
||||||
|
)
|
||||||
|
|
||||||
layout.separator_spacer()
|
layout.separator_spacer()
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
@ -120,43 +134,44 @@ def draw_header(self, context):
|
|||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|
||||||
for i, picker in enumerate(picker_group.pickers):
|
for i, picker in enumerate(picker_group.pickers):
|
||||||
row.operator('rigpicker.fit_picker', text=f'{i+1}').index=i
|
row.operator("rigpicker.fit_picker", text=f"{i+1}").index = i
|
||||||
|
|
||||||
|
row.operator("rigpicker.fit_picker", text="", icon="FULLSCREEN_ENTER").index = -1
|
||||||
|
|
||||||
row.operator('rigpicker.fit_picker', text='', icon='FULLSCREEN_ENTER').index = -1
|
|
||||||
|
|
||||||
|
|
||||||
def tools_from_context(context, mode=None):
|
def tools_from_context(context, mode=None):
|
||||||
sp = context.space_data
|
sp = context.space_data
|
||||||
if sp and sp.type == 'NODE_EDITOR' and sp.tree_type == 'RigPickerTree':
|
if sp and sp.type == "NODE_EDITOR" and sp.tree_type == "RigPickerTree":
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return NODE_PT_tools_active._tools_from_context(context, mode)
|
return NODE_PT_tools_active._tools_from_context(context, mode)
|
||||||
|
|
||||||
|
|
||||||
def tool_set_by_id(self, context):
|
def tool_set_by_id(self, context):
|
||||||
sd = context.space_data
|
sd = context.space_data
|
||||||
if sd and sd.type == 'NODE_EDITOR' and sd.tree_type == 'RigPickerTree':
|
if sd and sd.type == "NODE_EDITOR" and sd.tree_type == "RigPickerTree":
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
else:
|
else:
|
||||||
return self._execute(context)
|
return self._execute(context)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
sp = context.space_data
|
sp = context.space_data
|
||||||
if sp and sp.type == 'NODE_EDITOR' and sp.tree_type == 'RigPickerTree':
|
if sp and sp.type == "NODE_EDITOR" and sp.tree_type == "RigPickerTree":
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return self._poll(context)
|
return self._poll(context)
|
||||||
|
|
||||||
classes = (
|
|
||||||
RigPickerTree,
|
classes = (RigPickerTree, RP_MT_picker, RP_MT_animation)
|
||||||
RP_MT_picker,
|
|
||||||
RP_MT_animation
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
# Remove the tools inside the picker space
|
# Remove the tools inside the picker space
|
||||||
bpy.types.WM_OT_tool_set_by_id._execute = bpy.types.WM_OT_tool_set_by_id.execute #tool_set_by_id
|
bpy.types.WM_OT_tool_set_by_id._execute = (
|
||||||
|
bpy.types.WM_OT_tool_set_by_id.execute
|
||||||
|
) # tool_set_by_id
|
||||||
bpy.types.WM_OT_tool_set_by_id.execute = tool_set_by_id
|
bpy.types.WM_OT_tool_set_by_id.execute = tool_set_by_id
|
||||||
|
|
||||||
NODE_PT_tools_active._tools_from_context = NODE_PT_tools_active.tools_from_context
|
NODE_PT_tools_active._tools_from_context = NODE_PT_tools_active.tools_from_context
|
||||||
@ -168,15 +183,16 @@ def register():
|
|||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
||||||
bpy.types.WM_OT_tool_set_by_id.execute = bpy.types.WM_OT_tool_set_by_id._execute
|
bpy.types.WM_OT_tool_set_by_id.execute = bpy.types.WM_OT_tool_set_by_id._execute
|
||||||
del bpy.types.WM_OT_tool_set_by_id._execute
|
del bpy.types.WM_OT_tool_set_by_id._execute
|
||||||
|
|
||||||
NODE_PT_tools_active.tools_from_context = NODE_PT_tools_active._tools_from_context
|
NODE_PT_tools_active.tools_from_context = NODE_PT_tools_active._tools_from_context
|
||||||
del NODE_PT_tools_active._tools_from_context
|
del NODE_PT_tools_active._tools_from_context
|
||||||
|
|
||||||
NODE_HT_header.draw = NODE_HT_header._draw
|
NODE_HT_header.draw = NODE_HT_header._draw
|
||||||
del NODE_HT_header._draw
|
del NODE_HT_header._draw
|
||||||
|
|||||||
30
constants.py
30
constants.py
@ -1,6 +1,7 @@
|
|||||||
import gpu
|
import gpu
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
class LazyDict(dict):
|
class LazyDict(dict):
|
||||||
def __getitem__(self, k):
|
def __getitem__(self, k):
|
||||||
v = super().__getitem__(k)
|
v = super().__getitem__(k)
|
||||||
@ -19,11 +20,32 @@ PICKERS = {}
|
|||||||
|
|
||||||
|
|
||||||
MODULE_DIR = Path(__file__).parent
|
MODULE_DIR = Path(__file__).parent
|
||||||
SHADER_DIR = MODULE_DIR / 'shaders'
|
SHADER_DIR = MODULE_DIR / "shaders"
|
||||||
|
|
||||||
SHADERS = LazyDict()
|
SHADERS = LazyDict()
|
||||||
|
|
||||||
vertex_shader = Path(SHADER_DIR, "dash_shader.vert").read_text(encoding='utf-8')
|
vertex_shader = Path(SHADER_DIR, "dash_shader.vert").read_text(encoding="utf-8")
|
||||||
fragment_shader = Path(SHADER_DIR, "dash_shader.frag").read_text(encoding='utf-8')
|
fragment_shader = Path(SHADER_DIR, "dash_shader.frag").read_text(encoding="utf-8")
|
||||||
|
|
||||||
SHADERS['dashed_line'] = lambda : gpu.types.GPUShader(vertex_shader, fragment_shader)
|
|
||||||
|
def create_dashed_line_shader() -> gpu.types.GPUShader:
|
||||||
|
shader_info = gpu.types.GPUShaderCreateInfo()
|
||||||
|
|
||||||
|
shader_info.vertex_in(0, "VEC2", "pos")
|
||||||
|
shader_info.fragment_out(0, "VEC4", "fragColor")
|
||||||
|
shader_info.push_constant("VEC4", "color")
|
||||||
|
shader_info.push_constant("MAT4", "viewMatrix")
|
||||||
|
shader_info.push_constant("FLOAT", "dashSize")
|
||||||
|
shader_info.push_constant("FLOAT", "gapSize")
|
||||||
|
|
||||||
|
shader_info.vertex_source(vertex_shader)
|
||||||
|
shader_info.fragment_source(fragment_shader)
|
||||||
|
|
||||||
|
shader = gpu.shader.create_from_info(shader_info)
|
||||||
|
del shader_info
|
||||||
|
return shader
|
||||||
|
|
||||||
|
|
||||||
|
SHADERS["dashed_line"] = (
|
||||||
|
create_dashed_line_shader # lambda: gpu.types.GPUShader(vertex_shader, fragment_shader)
|
||||||
|
)
|
||||||
|
|||||||
@ -1,19 +1,23 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from .bl_utils import get_mat, get_collection_parents
|
from .bl_utils import get_mat, get_collection_parents
|
||||||
|
|
||||||
|
|
||||||
def get_picker_collection(ob=None):
|
def get_picker_collection(ob: bpy.types.Object | None = None):
|
||||||
"""Return the picker collection of an object"""
|
"""Return the picker collection of an object"""
|
||||||
|
|
||||||
if not ob:
|
if not ob:
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
|
|
||||||
|
if not ob:
|
||||||
|
raise Exception("No object in context")
|
||||||
|
|
||||||
for col in ob.users_collection:
|
for col in ob.users_collection:
|
||||||
if col.rig_picker.enabled:
|
if col.rig_picker.enabled:
|
||||||
return col
|
return col
|
||||||
|
|
||||||
if picker_col := next((c for c in get_collection_parents(col) if c.rig_picker.enabled), None):
|
if picker_col := next(
|
||||||
|
(c for c in get_collection_parents(col) if c.rig_picker.enabled), None
|
||||||
|
):
|
||||||
return picker_col
|
return picker_col
|
||||||
|
|
||||||
|
|
||||||
@ -22,10 +26,10 @@ def is_shape(ob):
|
|||||||
canvas = scn.rig_picker.canvas
|
canvas = scn.rig_picker.canvas
|
||||||
if not canvas or ob.hide_render:
|
if not canvas or ob.hide_render:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
shapes = {ob for col in canvas.users_collection for ob in col.all_objects}
|
shapes = {ob for col in canvas.users_collection for ob in col.all_objects}
|
||||||
|
|
||||||
if ob.type in ('MESH', 'CURVE', 'FONT') and ob in shapes:
|
if ob.type in ("MESH", "CURVE", "FONT") and ob in shapes:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -34,20 +38,20 @@ def is_shape(ob):
|
|||||||
def get_object_color(ob):
|
def get_object_color(ob):
|
||||||
if not ob.data.materials:
|
if not ob.data.materials:
|
||||||
return
|
return
|
||||||
|
|
||||||
mat = get_mat(ob)
|
mat = get_mat(ob)
|
||||||
if not mat or not mat.node_tree or not mat.node_tree.nodes:
|
if not mat or not mat.node_tree or not mat.node_tree.nodes:
|
||||||
return
|
return
|
||||||
|
|
||||||
emit_node = mat.node_tree.nodes.get('Emission')
|
emit_node = mat.node_tree.nodes.get("Emission")
|
||||||
if not emit_node:
|
if not emit_node:
|
||||||
return
|
return
|
||||||
|
|
||||||
return emit_node.inputs['Color'].default_value
|
return emit_node.inputs["Color"].default_value
|
||||||
|
|
||||||
|
|
||||||
def get_operator_from_id(idname):
|
def get_operator_from_id(idname):
|
||||||
if not '.' in idname:
|
if not "." in idname:
|
||||||
return
|
return
|
||||||
|
|
||||||
m, o = idname.split(".")
|
m, o = idname.split(".")
|
||||||
@ -56,5 +60,5 @@ def get_operator_from_id(idname):
|
|||||||
op.get_rna_type()
|
op.get_rna_type()
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
return op
|
return op
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
@ -30,94 +29,103 @@ def get_collection_parents(col, root=None, cols=None):
|
|||||||
cols = get_collection_parents(col, root=sub, cols=cols)
|
cols = get_collection_parents(col, root=sub, cols=cols)
|
||||||
return cols
|
return cols
|
||||||
|
|
||||||
|
|
||||||
def get_view_3d_override():
|
def get_view_3d_override():
|
||||||
windows = bpy.context.window_manager.windows
|
windows = bpy.context.window_manager.windows
|
||||||
areas = [a for w in windows for a in w.screen.areas if a.type == 'VIEW_3D']
|
areas = [a for w in windows for a in w.screen.areas if a.type == "VIEW_3D"]
|
||||||
|
|
||||||
if not areas:
|
if not areas:
|
||||||
print('No view 3d found')
|
print("No view 3d found")
|
||||||
return
|
return
|
||||||
|
|
||||||
view_3d = None
|
view_3d = None
|
||||||
for area in areas:
|
for area in areas:
|
||||||
if area.spaces.active.camera:
|
if area.spaces.active.camera:
|
||||||
view_3d = area
|
view_3d = area
|
||||||
|
|
||||||
if not view_3d:
|
|
||||||
view_3d = max(areas, key=lambda x :x.width)
|
|
||||||
|
|
||||||
return {'area': view_3d, 'region': view_3d.regions[-1]}
|
if not view_3d:
|
||||||
|
view_3d = max(areas, key=lambda x: x.width)
|
||||||
|
|
||||||
|
return {"area": view_3d, "region": view_3d.regions[-1]}
|
||||||
|
|
||||||
|
|
||||||
def get_mat(ob):
|
def get_mat(ob):
|
||||||
for sl in ob.material_slots:
|
for sl in ob.material_slots:
|
||||||
if sl.material:
|
if sl.material:
|
||||||
return sl.material
|
return sl.material
|
||||||
|
|
||||||
|
|
||||||
def link_mat_to_object(ob):
|
def link_mat_to_object(ob):
|
||||||
for sl in ob.material_slots:
|
for sl in ob.material_slots:
|
||||||
m = sl.material
|
m = sl.material
|
||||||
sl.link = 'OBJECT'
|
sl.link = "OBJECT"
|
||||||
sl.material = m
|
sl.material = m
|
||||||
|
|
||||||
|
|
||||||
def eval_attr(ob, name):
|
def eval_attr(ob, name):
|
||||||
resolved = ob
|
resolved = ob
|
||||||
for o in name.split("."):
|
for o in name.split("."):
|
||||||
resolved = getattr(resolved, o)
|
resolved = getattr(resolved, o)
|
||||||
return resolved
|
return resolved
|
||||||
|
|
||||||
|
|
||||||
def flip_name(name):
|
def flip_name(name):
|
||||||
if not name:
|
if not name:
|
||||||
return
|
return
|
||||||
|
|
||||||
if name.startswith('[') and name.endswith(']'): #It's a custom property
|
if name.startswith("[") and name.endswith("]"): # It's a custom property
|
||||||
flipped_name = bpy.utils.flip_name(name[:-2][2:])
|
flipped_name = bpy.utils.flip_name(name[:-2][2:])
|
||||||
return f'["{flipped_name}"]'
|
return f'["{flipped_name}"]'
|
||||||
else:
|
else:
|
||||||
return bpy.utils.flip_name(name)
|
return bpy.utils.flip_name(name)
|
||||||
|
|
||||||
def split_path(path) :
|
|
||||||
try :
|
def split_path(path):
|
||||||
|
try:
|
||||||
bone_name = path.split('["')[1].split('"]')[0]
|
bone_name = path.split('["')[1].split('"]')[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
bone_name = None
|
bone_name = None
|
||||||
|
|
||||||
try :
|
try:
|
||||||
prop_name = path.split('["')[2].split('"]')[0]
|
prop_name = path.split('["')[2].split('"]')[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
prop_name = None
|
prop_name = None
|
||||||
|
|
||||||
return bone_name, prop_name
|
return bone_name, prop_name
|
||||||
|
|
||||||
|
|
||||||
def hide_layers(args):
|
def hide_layers(args):
|
||||||
""" """
|
""" """
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
|
|
||||||
layers = []
|
layers = []
|
||||||
for bone in [b for b in ob.pose.bones if b.bone.select]:
|
for bone in [b for b in ob.pose.bones if b.bone.select]:
|
||||||
for i,l in enumerate(bone.bone.layers):
|
for i, l in enumerate(bone.bone.layers):
|
||||||
if l and i not in layers:
|
if l and i not in layers:
|
||||||
layers.append(i)
|
layers.append(i)
|
||||||
|
|
||||||
for i in layers:
|
for i in layers:
|
||||||
ob.data.layers[i] = not ob.data.layers[i]
|
ob.data.layers[i] = not ob.data.layers[i]
|
||||||
|
|
||||||
|
|
||||||
def select_layer(args):
|
def select_layer(args):
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
|
|
||||||
layers =[]
|
layers = []
|
||||||
for bone in [b for b in ob.pose.bones if b.bone.select]:
|
for bone in [b for b in ob.pose.bones if b.bone.select]:
|
||||||
bone_layers = [i for i,l in enumerate(bone.bone.layers) if l]
|
bone_layers = [i for i, l in enumerate(bone.bone.layers) if l]
|
||||||
|
|
||||||
for l in bone_layers:
|
for l in bone_layers:
|
||||||
if l not in layers:
|
if l not in layers:
|
||||||
layers.append(l)
|
layers.append(l)
|
||||||
|
|
||||||
for bone in ob.pose.bones:
|
for bone in ob.pose.bones:
|
||||||
bone_layers = [i for i,l in enumerate(bone.bone.layers) if l]
|
bone_layers = [i for i, l in enumerate(bone.bone.layers) if l]
|
||||||
|
|
||||||
if len(set(bone_layers).intersection(layers)):
|
if len(set(bone_layers).intersection(layers)):
|
||||||
bone.bone.select = True
|
bone.bone.select = True
|
||||||
|
|
||||||
|
|
||||||
def hide_bones(args):
|
def hide_bones(args):
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
selected_bone = [b for b in ob.pose.bones if b.bone.select]
|
selected_bone = [b for b in ob.pose.bones if b.bone.select]
|
||||||
@ -129,10 +137,11 @@ def hide_bones(args):
|
|||||||
for bone in selected_bone:
|
for bone in selected_bone:
|
||||||
bone.bone.hide = visibility
|
bone.bone.hide = visibility
|
||||||
|
|
||||||
|
|
||||||
def select_all(args):
|
def select_all(args):
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
shapes = ob.data.rig_picker['shapes']
|
shapes = ob.data.rig_picker["shapes"]
|
||||||
bones = [s['bone'] for s in shapes if s['shape_type']=='BONE']
|
bones = [s["bone"] for s in shapes if s["shape_type"] == "BONE"]
|
||||||
|
|
||||||
for bone_name in bones:
|
for bone_name in bones:
|
||||||
bone = ob.pose.bones.get(bone_name)
|
bone = ob.pose.bones.get(bone_name)
|
||||||
|
|||||||
@ -1,28 +1,31 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
from mathutils.geometry import intersect_line_line_2d
|
from mathutils.geometry import intersect_line_line_2d
|
||||||
|
|
||||||
|
|
||||||
def is_over_region(self,context,event):
|
def is_over_region(self, context, event):
|
||||||
inside = 2 < event.mouse_region_x < context.region.width -2 and \
|
inside = (
|
||||||
2 < event.mouse_region_y < context.region.height -2 and \
|
2 < event.mouse_region_x < context.region.width - 2
|
||||||
[a for a in context.screen.areas if a.as_pointer()==self.adress] and \
|
and 2 < event.mouse_region_y < context.region.height - 2
|
||||||
not context.screen.show_fullscreen
|
and [a for a in context.screen.areas if a.as_pointer() == self.adress]
|
||||||
|
and not context.screen.show_fullscreen
|
||||||
|
)
|
||||||
|
|
||||||
return inside
|
return inside
|
||||||
|
|
||||||
|
|
||||||
def bound_box_center(ob):
|
def bound_box_center(ob):
|
||||||
points = [ob.matrix_world@Vector(p) for p in ob.bound_box]
|
points = [ob.matrix_world @ Vector(p) for p in ob.bound_box]
|
||||||
|
|
||||||
x = [v[0] for v in points]
|
x = [v[0] for v in points]
|
||||||
y = [v[1] for v in points]
|
y = [v[1] for v in points]
|
||||||
z = [v[2] for v in points]
|
z = [v[2] for v in points]
|
||||||
|
|
||||||
return (sum(x) / len(points), sum(y) / len(points),sum(z) / len(points))
|
return (sum(x) / len(points), sum(y) / len(points), sum(z) / len(points))
|
||||||
|
|
||||||
|
|
||||||
def bounding_rect(points):
|
def bounding_rect(points):
|
||||||
x_points = sorted(p[0] for p in points)
|
x_points = sorted(p[0] for p in points)
|
||||||
y_points = sorted(p[1] for p in points)
|
y_points = sorted(p[1] for p in points)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -32,28 +35,31 @@ def bounding_rect(points):
|
|||||||
Vector((x_points[0], y_points[0])),
|
Vector((x_points[0], y_points[0])),
|
||||||
]
|
]
|
||||||
|
|
||||||
def intersect_rects(rect, border): # returns None if rectangles don't intersect
|
|
||||||
dx = min(border[1][0],rect[1][0]) - max(border[0][0],rect[0][0])
|
|
||||||
dy = min(border[0][1],rect[0][1]) - max(border[2][1],rect[2][1])
|
|
||||||
|
|
||||||
if (dx>=0) and (dy>=0):
|
def intersect_rects(rect, border): # returns None if rectangles don't intersect
|
||||||
return dx*dy
|
dx = min(border[1][0], rect[1][0]) - max(border[0][0], rect[0][0])
|
||||||
|
dy = min(border[0][1], rect[0][1]) - max(border[2][1], rect[2][1])
|
||||||
|
|
||||||
|
if (dx >= 0) and (dy >= 0):
|
||||||
|
return dx * dy
|
||||||
|
|
||||||
|
|
||||||
def point_inside_rect(point, rect):
|
def point_inside_rect(point, rect):
|
||||||
return rect[0][0]< point[0]< rect[1][0] and rect[2][1]< point[1]< rect[0][1]
|
return rect[0][0] < point[0] < rect[1][0] and rect[2][1] < point[1] < rect[0][1]
|
||||||
|
|
||||||
def point_over_shape(point,verts,loops,outside_point=(-1,-1)):
|
|
||||||
|
def point_over_shape(point, verts, loops, outside_point=(-1, -1)):
|
||||||
out = Vector(outside_point)
|
out = Vector(outside_point)
|
||||||
pt = Vector(point)
|
pt = Vector(point)
|
||||||
|
|
||||||
intersections = 0
|
intersections = 0
|
||||||
for loop in loops:
|
for loop in loops:
|
||||||
for i,p in enumerate(loop):
|
for i, p in enumerate(loop):
|
||||||
a = Vector(verts[loop[i-1]])
|
a = Vector(verts[loop[i - 1]])
|
||||||
b = Vector(verts[p])
|
b = Vector(verts[p])
|
||||||
|
|
||||||
if intersect_line_line_2d(pt,out,a,b):
|
if intersect_line_line_2d(pt, out, a, b):
|
||||||
intersections += 1
|
intersections += 1
|
||||||
|
|
||||||
if intersections%2 == 1: #chek if the nb of intersection is odd
|
if intersections % 2 == 1: # chek if the nb of intersection is odd
|
||||||
return True
|
return True
|
||||||
|
|||||||
453
core/picker.py
453
core/picker.py
@ -1,11 +1,13 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import gpu
|
import gpu
|
||||||
from gpu_extras.batch import batch_for_shader
|
from gpu_extras.batch import batch_for_shader
|
||||||
import blf
|
import blf
|
||||||
from mathutils import bvhtree, Vector, Color
|
from mathutils import bvhtree, Vector, Color
|
||||||
from mathutils.geometry import (intersect_point_quad_2d, intersect_point_tri_2d,
|
from mathutils.geometry import (
|
||||||
intersect_tri_tri_2d)
|
intersect_point_quad_2d,
|
||||||
|
intersect_point_tri_2d,
|
||||||
|
intersect_tri_tri_2d,
|
||||||
|
)
|
||||||
from ..constants import PICKERS
|
from ..constants import PICKERS
|
||||||
from .addon_utils import get_operator_from_id
|
from .addon_utils import get_operator_from_id
|
||||||
from .geometry_utils import bounding_rect
|
from .geometry_utils import bounding_rect
|
||||||
@ -15,13 +17,21 @@ import re
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
|
||||||
class Shape:
|
class Shape:
|
||||||
def __init__(self, picker, points, polygons=None, edges=None, tooltip='', color=None, source_name=''):
|
def __init__(
|
||||||
|
self,
|
||||||
self.type = 'display'
|
picker,
|
||||||
|
points,
|
||||||
|
polygons=None,
|
||||||
|
edges=None,
|
||||||
|
tooltip="",
|
||||||
|
color=None,
|
||||||
|
source_name="",
|
||||||
|
):
|
||||||
|
self.type = "display"
|
||||||
self.picker = picker
|
self.picker = picker
|
||||||
self.rig = picker.rig
|
self.rig = picker.rig
|
||||||
self.source_name = source_name
|
self.source_name = source_name
|
||||||
@ -29,11 +39,11 @@ class Shape:
|
|||||||
self.hover = False
|
self.hover = False
|
||||||
self.press = False
|
self.press = False
|
||||||
|
|
||||||
self.shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||||
self.shader.bind()
|
self.shader.bind()
|
||||||
|
|
||||||
#self.hover_shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
# self.hover_shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
||||||
#self.hover_shader.uniform_float("color", [1, 1, 1, 0.1])
|
# self.hover_shader.uniform_float("color", [1, 1, 1, 0.1])
|
||||||
|
|
||||||
self.color = color
|
self.color = color
|
||||||
self.hover_color = self.brighten_color(self.color)
|
self.hover_color = self.brighten_color(self.color)
|
||||||
@ -43,15 +53,19 @@ class Shape:
|
|||||||
self.polygons = polygons or []
|
self.polygons = polygons or []
|
||||||
self.edges = edges or []
|
self.edges = edges or []
|
||||||
|
|
||||||
self.p_batch = batch_for_shader(self.shader, 'TRIS', {"pos": self.points}, indices=self.polygons)
|
self.p_batch = batch_for_shader(
|
||||||
self.e_batch = batch_for_shader(self.shader, 'LINES', {"pos": self.points}, indices=self.edges)
|
self.shader, "TRIS", {"pos": self.points}, indices=self.polygons
|
||||||
|
)
|
||||||
|
self.e_batch = batch_for_shader(
|
||||||
|
self.shader, "LINES", {"pos": self.points}, indices=self.edges
|
||||||
|
)
|
||||||
|
|
||||||
self.rect = bounding_rect(points)
|
self.rect = bounding_rect(points)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color(self):
|
def color(self):
|
||||||
return self._color
|
return self._color
|
||||||
|
|
||||||
def brighten_color(self, color):
|
def brighten_color(self, color):
|
||||||
brighten_color = Color(color[:3])
|
brighten_color = Color(color[:3])
|
||||||
brighten_color.v += 0.05
|
brighten_color.v += 0.05
|
||||||
@ -70,16 +84,15 @@ class Shape:
|
|||||||
elif len(color) == 4:
|
elif len(color) == 4:
|
||||||
color = list(color)
|
color = list(color)
|
||||||
else:
|
else:
|
||||||
raise Exception('color must have a len of 3 or 4')
|
raise Exception("color must have a len of 3 or 4")
|
||||||
else:
|
else:
|
||||||
raise Exception(f'color is {type(color)} must be None or (tuple, list)')
|
raise Exception(f"color is {type(color)} must be None or (tuple, list)")
|
||||||
|
|
||||||
#self.shader.uniform_float("color", color)
|
# self.shader.uniform_float("color", color)
|
||||||
self._color = color
|
self._color = color
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
|
# self.shader.bind()
|
||||||
#self.shader.bind()
|
|
||||||
self.shader.uniform_float("color", self.color)
|
self.shader.uniform_float("color", self.color)
|
||||||
|
|
||||||
if self.polygons:
|
if self.polygons:
|
||||||
@ -92,28 +105,45 @@ class Shape:
|
|||||||
if not intersect_point_quad_2d(location, *self.rect):
|
if not intersect_point_quad_2d(location, *self.rect):
|
||||||
self.hover = False
|
self.hover = False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for p in self.polygons:
|
for p in self.polygons:
|
||||||
if intersect_point_tri_2d(location, *[self.points[i] for i in p]):
|
if intersect_point_tri_2d(location, *[self.points[i] for i in p]):
|
||||||
self.hover = True
|
self.hover = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.hover = False
|
self.hover = False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def press_event(self, mode='SET'):
|
def press_event(self, mode="SET"):
|
||||||
self.press = True
|
self.press = True
|
||||||
|
|
||||||
def release_event(self, mode='SET'):
|
def release_event(self, mode="SET"):
|
||||||
self.press = False
|
self.press = False
|
||||||
|
|
||||||
|
|
||||||
class BoneShape(Shape):
|
class BoneShape(Shape):
|
||||||
def __init__(self, picker, points, polygons, edges, bone, tooltip='', color=None, source_name=''):
|
def __init__(
|
||||||
super().__init__(picker, points=points, polygons=polygons, edges=edges,
|
self,
|
||||||
tooltip=tooltip, color=color, source_name=source_name)
|
picker,
|
||||||
|
points,
|
||||||
|
polygons,
|
||||||
|
edges,
|
||||||
|
bone,
|
||||||
|
tooltip="",
|
||||||
|
color=None,
|
||||||
|
source_name="",
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
picker,
|
||||||
|
points=points,
|
||||||
|
polygons=polygons,
|
||||||
|
edges=edges,
|
||||||
|
tooltip=tooltip,
|
||||||
|
color=color,
|
||||||
|
source_name=source_name,
|
||||||
|
)
|
||||||
|
|
||||||
self.type = 'bone'
|
self.type = "bone"
|
||||||
self.bone = bone
|
self.bone = bone
|
||||||
self.active_color = [1, 1, 1, 0.1]
|
self.active_color = [1, 1, 1, 0.1]
|
||||||
self.select_color = self.brighten_color(self.hover_color)
|
self.select_color = self.brighten_color(self.hover_color)
|
||||||
@ -125,23 +155,29 @@ class BoneShape(Shape):
|
|||||||
if not self.bone:
|
if not self.bone:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.bone in (bpy.context.selected_pose_bones or []) #self.bone.bone.select
|
return self.bone in (
|
||||||
|
bpy.context.selected_pose_bones or []
|
||||||
|
) # self.bone.bone.select
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active(self):
|
def active(self):
|
||||||
if not self.bone:
|
if not self.bone:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.bone == bpy.context.active_pose_bone #self.rig.data.bones.active == self.bone.bone
|
return (
|
||||||
|
self.bone == bpy.context.active_pose_bone
|
||||||
|
) # self.rig.data.bones.active == self.bone.bone
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hide(self):
|
def hide(self):
|
||||||
if not self.bone:
|
if not self.bone:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
#return self.bone not in (bpy.context.visible_pose_bones or [])
|
# return self.bone not in (bpy.context.visible_pose_bones or [])
|
||||||
|
|
||||||
return self.bone.bone.hide or not any(l.is_visible for l in self.bone.bone.collections)
|
return self.bone.bone.hide or not any(
|
||||||
|
l.is_visible for l in self.bone.bone.collections
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bone_color(self):
|
def bone_color(self):
|
||||||
@ -149,45 +185,44 @@ class BoneShape(Shape):
|
|||||||
return [0, 0, 0, 1]
|
return [0, 0, 0, 1]
|
||||||
|
|
||||||
if self.select and self.active:
|
if self.select and self.active:
|
||||||
return self.bone_colors['active']
|
return self.bone_colors["active"]
|
||||||
elif self.select:
|
elif self.select:
|
||||||
return self.bone_colors['select']
|
return self.bone_colors["select"]
|
||||||
elif self.hide:
|
elif self.hide:
|
||||||
return self.bone_colors['hide']
|
return self.bone_colors["hide"]
|
||||||
else:
|
else:
|
||||||
return self.bone_colors['normal']
|
return self.bone_colors["normal"]
|
||||||
|
|
||||||
def get_bone_colors(self):
|
def get_bone_colors(self):
|
||||||
|
theme = bpy.context.preferences.themes["Default"]
|
||||||
theme = bpy.context.preferences.themes['Default']
|
|
||||||
bone_colors = {
|
bone_colors = {
|
||||||
'select': [*theme.view_3d.bone_pose, 1],
|
"select": [*theme.view_3d.bone_pose, 1],
|
||||||
'normal': [0.05, 0.05, 0.05, 1],
|
"normal": [0.05, 0.05, 0.05, 1],
|
||||||
'active': [*theme.view_3d.bone_pose_active, 1],
|
"active": [*theme.view_3d.bone_pose_active, 1],
|
||||||
'hide': [0.85, 0.85, 0.85, 0.2],
|
"hide": [0.85, 0.85, 0.85, 0.2],
|
||||||
}
|
}
|
||||||
|
|
||||||
if not self.bone:
|
if not self.bone:
|
||||||
return bone_colors
|
return bone_colors
|
||||||
|
|
||||||
if self.bone.color.palette == 'CUSTOM':
|
if self.bone.color.palette == "CUSTOM":
|
||||||
bone_color = self.bone
|
bone_color = self.bone
|
||||||
|
|
||||||
elif self.bone.color.palette == 'DEFAULT':
|
elif self.bone.color.palette == "DEFAULT":
|
||||||
bone_color = self.bone.bone
|
bone_color = self.bone.bone
|
||||||
|
|
||||||
normal_color = bone_color.color.custom.normal.copy()
|
normal_color = bone_color.color.custom.normal.copy()
|
||||||
normal_color.s *= 0.75
|
normal_color.s *= 0.75
|
||||||
|
|
||||||
bone_colors['normal'] = [*normal_color, 1]
|
bone_colors["normal"] = [*normal_color, 1]
|
||||||
bone_colors['select'] = [*bone_color.color.custom.select, 1]
|
bone_colors["select"] = [*bone_color.color.custom.select, 1]
|
||||||
bone_colors['active'] = [*bone_color.color.custom.active, 1]
|
bone_colors["active"] = [*bone_color.color.custom.active, 1]
|
||||||
bone_colors['hide'] = [*normal_color, 0.1]
|
bone_colors["hide"] = [*normal_color, 0.1]
|
||||||
|
|
||||||
return bone_colors
|
return bone_colors
|
||||||
|
|
||||||
def draw_hided(self):
|
def draw_hided(self):
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set("ALPHA")
|
||||||
gpu.state.line_width_set(1.0)
|
gpu.state.line_width_set(1.0)
|
||||||
|
|
||||||
line_color = (1, 1, 1, 0.1)
|
line_color = (1, 1, 1, 0.1)
|
||||||
@ -200,17 +235,17 @@ class BoneShape(Shape):
|
|||||||
|
|
||||||
self.shader.uniform_float("color", (*color[:3], 0.5))
|
self.shader.uniform_float("color", (*color[:3], 0.5))
|
||||||
self.p_batch.draw(self.shader)
|
self.p_batch.draw(self.shader)
|
||||||
|
|
||||||
self.shader.uniform_float("color", line_color)
|
self.shader.uniform_float("color", line_color)
|
||||||
self.e_batch.draw(self.shader)
|
self.e_batch.draw(self.shader)
|
||||||
|
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set("NONE")
|
||||||
|
|
||||||
def draw_zero_scaled(self):
|
def draw_zero_scaled(self):
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set("ALPHA")
|
||||||
gpu.state.line_width_set(1.0)
|
gpu.state.line_width_set(1.0)
|
||||||
|
|
||||||
line_color = (*self.bone_colors['normal'][:3], 0.2)
|
line_color = (*self.bone_colors["normal"][:3], 0.2)
|
||||||
color = Color(self.color[:3])
|
color = Color(self.color[:3])
|
||||||
if self.hover or self.select:
|
if self.hover or self.select:
|
||||||
color.v += 0.05
|
color.v += 0.05
|
||||||
@ -219,14 +254,14 @@ class BoneShape(Shape):
|
|||||||
|
|
||||||
self.shader.uniform_float("color", (*color[:3], 0.5))
|
self.shader.uniform_float("color", (*color[:3], 0.5))
|
||||||
self.p_batch.draw(self.shader)
|
self.p_batch.draw(self.shader)
|
||||||
|
|
||||||
self.shader.uniform_float("color", line_color)
|
self.shader.uniform_float("color", line_color)
|
||||||
self.e_batch.draw(self.shader)
|
self.e_batch.draw(self.shader)
|
||||||
|
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set("NONE")
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set("ALPHA")
|
||||||
gpu.state.line_width_set(1.0)
|
gpu.state.line_width_set(1.0)
|
||||||
|
|
||||||
if self.hide:
|
if self.hide:
|
||||||
@ -244,9 +279,9 @@ class BoneShape(Shape):
|
|||||||
|
|
||||||
self.shader.uniform_float("color", color)
|
self.shader.uniform_float("color", color)
|
||||||
self.p_batch.draw(self.shader)
|
self.p_batch.draw(self.shader)
|
||||||
|
|
||||||
# Draw Outline
|
# Draw Outline
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set("NONE")
|
||||||
if self.select or self.active:
|
if self.select or self.active:
|
||||||
gpu.state.line_width_set(2.0)
|
gpu.state.line_width_set(2.0)
|
||||||
|
|
||||||
@ -254,51 +289,48 @@ class BoneShape(Shape):
|
|||||||
self.e_batch.draw(self.shader)
|
self.e_batch.draw(self.shader)
|
||||||
|
|
||||||
gpu.state.line_width_set(1.0)
|
gpu.state.line_width_set(1.0)
|
||||||
|
|
||||||
def assign_bone_event(self):
|
|
||||||
|
|
||||||
#print('assign_bone_event', self)
|
def assign_bone_event(self):
|
||||||
|
# print('assign_bone_event', self)
|
||||||
|
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
rig = self.picker.rig
|
rig = self.picker.rig
|
||||||
source_object = scn.objects.get(self.source_name)
|
source_object = scn.objects.get(self.source_name)
|
||||||
if not source_object:
|
if not source_object:
|
||||||
print(f'Source object {self.source_name} not found')
|
print(f"Source object {self.source_name} not found")
|
||||||
return
|
|
||||||
|
|
||||||
active_bone = rig.data.bones.active
|
|
||||||
if not active_bone:
|
|
||||||
print('You need to have an active bone')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
#print(active_bone, source_object)
|
active_bone = rig.data.bones.active
|
||||||
#print(rig)
|
if not active_bone:
|
||||||
|
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.name = rig.data.bones.active.name
|
||||||
source_object.rig_picker.name = rig.data.bones.active.name
|
source_object.rig_picker.name = rig.data.bones.active.name
|
||||||
|
|
||||||
def release_event(self, mode='SET'):
|
def release_event(self, mode="SET"):
|
||||||
super().release_event(mode)
|
super().release_event(mode)
|
||||||
|
|
||||||
if self.hide or not self.bone:
|
if self.hide or not self.bone:
|
||||||
return
|
return
|
||||||
|
|
||||||
select = True
|
select = True
|
||||||
if mode == 'SUBSTRACT':
|
if mode == "SUBSTRACT":
|
||||||
select = False
|
select = False
|
||||||
|
|
||||||
self.bone.bone.select = select
|
self.rig.pose.bones.get(self.bone.bone.name).select = select
|
||||||
if self.hover:
|
if self.hover:
|
||||||
|
if mode != "SUBSTRACT":
|
||||||
if mode != 'SUBSTRACT':
|
|
||||||
self.rig.data.bones.active = self.bone.bone
|
self.rig.data.bones.active = self.bone.bone
|
||||||
|
|
||||||
|
def border_select(self, border, mode="SET"):
|
||||||
def border_select(self, border, mode='SET'):
|
|
||||||
if not self.bone:
|
if not self.bone:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.hide:
|
if self.hide:
|
||||||
self.bone.bone.select = False
|
self.rig.pose.bones.get(self.bone.bone.name).select = False
|
||||||
return
|
return
|
||||||
|
|
||||||
rect_tri1 = self.rect[0], self.rect[1], self.rect[2]
|
rect_tri1 = self.rect[0], self.rect[1], self.rect[2]
|
||||||
@ -307,77 +339,79 @@ class BoneShape(Shape):
|
|||||||
border_tri1 = border[0], border[1], border[2]
|
border_tri1 = border[0], border[1], border[2]
|
||||||
border_tri2 = border[2], border[3], border[0]
|
border_tri2 = border[2], border[3], border[0]
|
||||||
|
|
||||||
if (not intersect_tri_tri_2d(*border_tri1, *rect_tri1) and
|
if (
|
||||||
not intersect_tri_tri_2d(*border_tri1, *rect_tri2) and
|
not intersect_tri_tri_2d(*border_tri1, *rect_tri1)
|
||||||
not intersect_tri_tri_2d(*border_tri2, *rect_tri1) and
|
and not intersect_tri_tri_2d(*border_tri1, *rect_tri2)
|
||||||
not intersect_tri_tri_2d(*border_tri2, *rect_tri2)):
|
and not intersect_tri_tri_2d(*border_tri2, *rect_tri1)
|
||||||
|
and not intersect_tri_tri_2d(*border_tri2, *rect_tri2)
|
||||||
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
select = True
|
select = True
|
||||||
if mode == 'SUBSTRACT':
|
if mode == "SUBSTRACT":
|
||||||
select = False
|
select = False
|
||||||
|
|
||||||
for polygon in self.polygons:
|
for polygon in self.polygons:
|
||||||
points = [self.points[i] for i in polygon]
|
points = [self.points[i] for i in polygon]
|
||||||
|
|
||||||
if intersect_tri_tri_2d(*border_tri1, *points):
|
if intersect_tri_tri_2d(*border_tri1, *points):
|
||||||
self.bone.bone.select = select
|
self.rig.pose.bones.get(self.bone.bone.name).select = select
|
||||||
return
|
return
|
||||||
|
|
||||||
if intersect_tri_tri_2d(*border_tri2, *points):
|
if intersect_tri_tri_2d(*border_tri2, *points):
|
||||||
self.bone.bone.select = select
|
self.rig.pose.bones.get(self.bone.bone.name).select = select
|
||||||
return
|
return
|
||||||
|
|
||||||
'''
|
|
||||||
for b in border:
|
|
||||||
if intersect_point_tri_2d(b, *points):
|
|
||||||
self.bone.bone.select = select
|
|
||||||
return
|
|
||||||
|
|
||||||
for p in points:
|
|
||||||
if intersect_point_quad_2d(p, *border):
|
|
||||||
self.bone.bone.select = select
|
|
||||||
return
|
|
||||||
'''
|
|
||||||
|
|
||||||
class OperatorShape(Shape):
|
class OperatorShape(Shape):
|
||||||
def __init__(self, picker, points, polygons, operator, tooltip='', color=None, source_name=''):
|
def __init__(
|
||||||
super().__init__(picker, points=points, polygons=polygons, tooltip=tooltip,
|
self, picker, points, polygons, operator, tooltip="", color=None, source_name=""
|
||||||
color=color, source_name=source_name)
|
):
|
||||||
|
super().__init__(
|
||||||
|
picker,
|
||||||
|
points=points,
|
||||||
|
polygons=polygons,
|
||||||
|
tooltip=tooltip,
|
||||||
|
color=color,
|
||||||
|
source_name=source_name,
|
||||||
|
)
|
||||||
|
|
||||||
self.type = 'operator'
|
self.type = "operator"
|
||||||
self.active_color = [1, 1, 1, 0.15]
|
self.active_color = [1, 1, 1, 0.15]
|
||||||
self.press_color = [0, 0, 0, 0.25]
|
self.press_color = [0, 0, 0, 0.25]
|
||||||
self.operator = operator
|
self.operator = operator
|
||||||
#self.arguments = arguments#{k:eval(v)}
|
# self.arguments = arguments#{k:eval(v)}
|
||||||
#self.operator = get_operator_from_id(self.operator)
|
# self.operator = get_operator_from_id(self.operator)
|
||||||
|
|
||||||
if not tooltip:
|
if not tooltip:
|
||||||
self.tooltip = self.operator.replace('bpy.ops.', '').replace("'INVOKE_DEFAULT', ", '')
|
self.tooltip = self.operator.replace("bpy.ops.", "").replace(
|
||||||
|
"'INVOKE_DEFAULT', ", ""
|
||||||
|
)
|
||||||
|
|
||||||
#self.reg_args = re.compile(r'(\w+)=')
|
# self.reg_args = re.compile(r'(\w+)=')
|
||||||
'''
|
|
||||||
|
"""
|
||||||
def parse_args(self):
|
def parse_args(self):
|
||||||
|
|
||||||
args = self.reg_args.split(self.arguments)[1:]
|
args = self.reg_args.split(self.arguments)[1:]
|
||||||
#print(args, zip(args[::2], args[1::2]))
|
#print(args, zip(args[::2], args[1::2]))
|
||||||
return {k: eval(v) for k, v in zip(args[::2], args[1::2])}
|
return {k: eval(v) for k, v in zip(args[::2], args[1::2])}
|
||||||
#return {k:eval(v) for k, v in self.reg_args.split(self.arguments)}
|
#return {k:eval(v) for k, v in self.reg_args.split(self.arguments)}
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def release_event(self, mode='SET'):
|
def release_event(self, mode="SET"):
|
||||||
super().release_event(mode)
|
super().release_event(mode)
|
||||||
|
|
||||||
#args = self.parse_args()
|
# args = self.parse_args()
|
||||||
if not self.operator:
|
if not self.operator:
|
||||||
return
|
return
|
||||||
|
|
||||||
exec(self.operator)
|
exec(self.operator)
|
||||||
#f'bpy.ops;{idname}'
|
# f'bpy.ops;{idname}'
|
||||||
|
|
||||||
#print(self.idname)
|
# print(self.idname)
|
||||||
#print(self.arguments)
|
# print(self.arguments)
|
||||||
#else:
|
# else:
|
||||||
# self.bone.bone.select = False
|
# self.bone.bone.select = False
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
@ -390,10 +424,10 @@ class OperatorShape(Shape):
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set("ALPHA")
|
||||||
self.shader.uniform_float("color", color)
|
self.shader.uniform_float("color", color)
|
||||||
self.p_batch.draw(self.shader)
|
self.p_batch.draw(self.shader)
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set("NONE")
|
||||||
|
|
||||||
|
|
||||||
class Picker:
|
class Picker:
|
||||||
@ -406,48 +440,48 @@ class Picker:
|
|||||||
self.shapes = []
|
self.shapes = []
|
||||||
self.box_select = None
|
self.box_select = None
|
||||||
self.hover_shape = None
|
self.hover_shape = None
|
||||||
self.shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||||
|
|
||||||
self.mouse = None
|
self.mouse = None
|
||||||
|
|
||||||
for shape_data in shapes:
|
for shape_data in shapes:
|
||||||
if not shape_data['points']:
|
if not shape_data["points"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if shape_data['type'] in ('CANVAS', 'DISPLAY'):
|
if shape_data["type"] in ("CANVAS", "DISPLAY"):
|
||||||
shape = Shape(
|
shape = Shape(
|
||||||
self,
|
self,
|
||||||
points=shape_data['points'],
|
points=shape_data["points"],
|
||||||
polygons=shape_data['polygons'],
|
polygons=shape_data["polygons"],
|
||||||
edges=shape_data['edges'],
|
edges=shape_data["edges"],
|
||||||
color=shape_data['color']
|
color=shape_data["color"],
|
||||||
)
|
)
|
||||||
|
|
||||||
elif shape_data['type'] == 'BONE':
|
elif shape_data["type"] == "BONE":
|
||||||
bone = rig.pose.bones.get(shape_data['bone'])
|
bone = rig.pose.bones.get(shape_data["bone"])
|
||||||
#if not bone:
|
# if not bone:
|
||||||
# print(f'Bone {shape_data["bone"]} not exist')
|
# print(f'Bone {shape_data["bone"]} not exist')
|
||||||
# continue
|
# continue
|
||||||
|
|
||||||
shape = BoneShape(
|
shape = BoneShape(
|
||||||
self,
|
self,
|
||||||
source_name=shape_data['source_name'],
|
source_name=shape_data["source_name"],
|
||||||
points=shape_data['points'],
|
points=shape_data["points"],
|
||||||
polygons=shape_data['polygons'],
|
polygons=shape_data["polygons"],
|
||||||
edges=shape_data['edges'],
|
edges=shape_data["edges"],
|
||||||
bone=bone,
|
bone=bone,
|
||||||
color=shape_data['color']
|
color=shape_data["color"],
|
||||||
)
|
)
|
||||||
|
|
||||||
elif shape_data['type'] == 'OPERATOR':
|
elif shape_data["type"] == "OPERATOR":
|
||||||
shape = OperatorShape(
|
shape = OperatorShape(
|
||||||
self,
|
self,
|
||||||
source_name=shape_data['source_name'],
|
source_name=shape_data["source_name"],
|
||||||
points=shape_data['points'],
|
points=shape_data["points"],
|
||||||
polygons=shape_data['polygons'],
|
polygons=shape_data["polygons"],
|
||||||
operator=shape_data['operator'],
|
operator=shape_data["operator"],
|
||||||
color=shape_data['color'],
|
color=shape_data["color"],
|
||||||
tooltip=shape_data['tooltip'],
|
tooltip=shape_data["tooltip"],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.shapes.append(shape)
|
self.shapes.append(shape)
|
||||||
@ -456,36 +490,34 @@ class Picker:
|
|||||||
|
|
||||||
def assign_bone_event(self):
|
def assign_bone_event(self):
|
||||||
for shape in self.shapes:
|
for shape in self.shapes:
|
||||||
if shape.type == 'bone' and shape.hover:
|
if shape.type == "bone" and shape.hover:
|
||||||
shape.assign_bone_event()
|
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'):
|
def press_event(self, mode="SET"):
|
||||||
for shape in self.shapes:
|
for shape in self.shapes:
|
||||||
#print(s)
|
# print(s)
|
||||||
if shape.hover:
|
if shape.hover:
|
||||||
shape.press_event(mode)
|
shape.press_event(mode)
|
||||||
else:
|
else:
|
||||||
shape.press = False
|
shape.press = False
|
||||||
|
|
||||||
def release_event(self, mode='SET'):
|
def release_event(self, mode="SET"):
|
||||||
|
# bpy.ops.pose.select_all(action='DESELECT')
|
||||||
|
|
||||||
|
# print('PICKER release event', mode)
|
||||||
#bpy.ops.pose.select_all(action='DESELECT')
|
# print(f'type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
|
||||||
|
|
||||||
#print('PICKER release event', mode)
|
|
||||||
#print(f'type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
|
|
||||||
|
|
||||||
for shape in self.shapes:
|
for shape in self.shapes:
|
||||||
if shape.hover:
|
if shape.hover:
|
||||||
shape.release_event(mode)
|
shape.release_event(mode)
|
||||||
|
|
||||||
shape.press = False
|
|
||||||
|
|
||||||
#bpy.context.area.tag_redraw()
|
|
||||||
|
|
||||||
'''
|
shape.press = False
|
||||||
|
|
||||||
|
# bpy.context.area.tag_redraw()
|
||||||
|
|
||||||
|
"""
|
||||||
picker.tooltip_event(event='SHOW')
|
picker.tooltip_event(event='SHOW')
|
||||||
region.tag_redraw()
|
region.tag_redraw()
|
||||||
|
|
||||||
@ -495,8 +527,9 @@ class Picker:
|
|||||||
|
|
||||||
picker.tooltip_event(event='HIDE')
|
picker.tooltip_event(event='HIDE')
|
||||||
bpy.app.timers.register(partial(tooltip, context.region), first_interval=1)
|
bpy.app.timers.register(partial(tooltip, context.region), first_interval=1)
|
||||||
'''
|
"""
|
||||||
'''
|
|
||||||
|
"""
|
||||||
def tooltip_event(self, event):
|
def tooltip_event(self, event):
|
||||||
|
|
||||||
|
|
||||||
@ -508,7 +541,7 @@ class Picker:
|
|||||||
self.tooltip = self.hover_shape.bone.name
|
self.tooltip = self.hover_shape.bone.name
|
||||||
|
|
||||||
#bpy.context.region.tag_redraw()
|
#bpy.context.region.tag_redraw()
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def border_select(self, border, mode):
|
def border_select(self, border, mode):
|
||||||
border = [Vector(b) - Vector(self.translation) for b in border]
|
border = [Vector(b) - Vector(self.translation) for b in border]
|
||||||
@ -516,7 +549,7 @@ class Picker:
|
|||||||
for shape in self.shapes:
|
for shape in self.shapes:
|
||||||
shape.press = False
|
shape.press = False
|
||||||
shape.hover = False
|
shape.hover = False
|
||||||
if shape.type != 'bone':
|
if shape.type != "bone":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
shape.border_select(border, mode)
|
shape.border_select(border, mode)
|
||||||
@ -531,16 +564,16 @@ class Picker:
|
|||||||
elif shape.move_event(self.mouse):
|
elif shape.move_event(self.mouse):
|
||||||
self.hover_shape = shape
|
self.hover_shape = shape
|
||||||
|
|
||||||
#if point_inside_rect(self.end, rect):
|
# if point_inside_rect(self.end, rect):
|
||||||
# over = point_over_shape(self.end,points, edges)
|
# over = point_over_shape(self.end,points, edges)
|
||||||
|
|
||||||
#if bpy.app.timers.is_registered(self.tooltip_event):
|
# if bpy.app.timers.is_registered(self.tooltip_event):
|
||||||
#try:
|
# try:
|
||||||
# bpy.app.timers.unregister(self.tooltip_event)
|
# bpy.app.timers.unregister(self.tooltip_event)
|
||||||
#except:
|
# except:
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
#bpy.app.timers.register(self.tooltip_event, first_interval=1)
|
# bpy.app.timers.register(self.tooltip_event, first_interval=1)
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
with gpu.matrix.push_pop():
|
with gpu.matrix.push_pop():
|
||||||
@ -564,8 +597,7 @@ class Picker:
|
|||||||
|
|
||||||
class PickerGroup:
|
class PickerGroup:
|
||||||
def __init__(self, rig, pickers):
|
def __init__(self, rig, pickers):
|
||||||
|
# self.view_location = Vector((0, 0))
|
||||||
#self.view_location = Vector((0, 0))
|
|
||||||
self.region = bpy.context.region
|
self.region = bpy.context.region
|
||||||
self.rig = rig
|
self.rig = rig
|
||||||
self.pickers = []
|
self.pickers = []
|
||||||
@ -577,13 +609,13 @@ class PickerGroup:
|
|||||||
|
|
||||||
self.tooltip_shape = None
|
self.tooltip_shape = None
|
||||||
self.tooltip_mouse = Vector((0, 0))
|
self.tooltip_mouse = Vector((0, 0))
|
||||||
self.tooltip = ''
|
self.tooltip = ""
|
||||||
|
|
||||||
self.timer = None
|
self.timer = None
|
||||||
|
|
||||||
for picker in pickers:
|
for picker in pickers:
|
||||||
self.add_picker(picker)
|
self.add_picker(picker)
|
||||||
|
|
||||||
def add_picker(self, picker):
|
def add_picker(self, picker):
|
||||||
self.pickers.append(Picker(self, self.rig, picker))
|
self.pickers.append(Picker(self, self.rig, picker))
|
||||||
|
|
||||||
@ -592,12 +624,12 @@ class PickerGroup:
|
|||||||
for picker in self.pickers:
|
for picker in self.pickers:
|
||||||
height = picker.rect[1][1] - picker.rect[-1][1]
|
height = picker.rect[1][1] - picker.rect[-1][1]
|
||||||
|
|
||||||
picker.translation = Vector((0, -y-height*0.5))
|
picker.translation = Vector((0, -y - height * 0.5))
|
||||||
picker.draw()
|
picker.draw()
|
||||||
|
|
||||||
y += height + 50
|
y += height + 50
|
||||||
|
|
||||||
#break #TODO for now only draw first picker
|
# break #TODO for now only draw first picker
|
||||||
|
|
||||||
def move_event(self, mouse):
|
def move_event(self, mouse):
|
||||||
self.mouse = mouse
|
self.mouse = mouse
|
||||||
@ -618,14 +650,14 @@ class PickerGroup:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
picker.move_event(self.location)
|
picker.move_event(self.location)
|
||||||
|
|
||||||
if picker.hover_shape:
|
if picker.hover_shape:
|
||||||
hover_shape = picker.hover_shape
|
hover_shape = picker.hover_shape
|
||||||
|
|
||||||
self.hover_shape = hover_shape
|
self.hover_shape = hover_shape
|
||||||
|
|
||||||
if self.tooltip_shape is not self.hover_shape:
|
if self.tooltip_shape is not self.hover_shape:
|
||||||
self.tooltip = ''
|
self.tooltip = ""
|
||||||
|
|
||||||
if self.timer:
|
if self.timer:
|
||||||
self.timer.cancel()
|
self.timer.cancel()
|
||||||
@ -633,8 +665,8 @@ class PickerGroup:
|
|||||||
self.timer = threading.Timer(0.4, self.tooltip_event)
|
self.timer = threading.Timer(0.4, self.tooltip_event)
|
||||||
self.timer.start()
|
self.timer.start()
|
||||||
|
|
||||||
def press_event(self, mode='SET'):
|
def press_event(self, mode="SET"):
|
||||||
#self.clear_tooltip()
|
# self.clear_tooltip()
|
||||||
|
|
||||||
for picker in self.pickers:
|
for picker in self.pickers:
|
||||||
if picker.under_mouse(self.location):
|
if picker.under_mouse(self.location):
|
||||||
@ -643,9 +675,9 @@ class PickerGroup:
|
|||||||
for shape in picker.shapes:
|
for shape in picker.shapes:
|
||||||
shape.press = False
|
shape.press = False
|
||||||
|
|
||||||
def release_event(self, mode='SET'):
|
def release_event(self, mode="SET"):
|
||||||
if mode == 'SET':
|
if mode == "SET":
|
||||||
for bone in self.rig.data.bones:
|
for bone in self.rig.pose.bones:
|
||||||
bone.select = False
|
bone.select = False
|
||||||
|
|
||||||
for picker in self.pickers:
|
for picker in self.pickers:
|
||||||
@ -663,45 +695,46 @@ class PickerGroup:
|
|||||||
def border_select(self, border, mode):
|
def border_select(self, border, mode):
|
||||||
border = [self.region.view2d.region_to_view(*b) for b in border]
|
border = [self.region.view2d.region_to_view(*b) for b in border]
|
||||||
|
|
||||||
if mode == 'SET':
|
if mode == "SET":
|
||||||
for bone in self.rig.data.bones:
|
for bone in self.rig.pose.bones:
|
||||||
bone.select = False
|
bone.select = False
|
||||||
|
|
||||||
for picker in self.pickers:
|
for picker in self.pickers:
|
||||||
picker.border_select(border, mode)
|
picker.border_select(border, mode)
|
||||||
|
|
||||||
def clear_tooltip(self):
|
def clear_tooltip(self):
|
||||||
self.tooltip = ''
|
self.tooltip = ""
|
||||||
self.tooltip_shape = None
|
self.tooltip_shape = None
|
||||||
self.timer.cancel()
|
self.timer.cancel()
|
||||||
self.region.tag_redraw()
|
self.region.tag_redraw()
|
||||||
|
|
||||||
def tooltip_event(self):
|
def tooltip_event(self):
|
||||||
#print('Tooltip Event', self)
|
# print('Tooltip Event', self)
|
||||||
|
|
||||||
#print(self.hover_shape, self.hover_shape.type)
|
# print(self.hover_shape, self.hover_shape.type)
|
||||||
|
|
||||||
if self.hover_shape and self.hover_shape.type != 'display':
|
if self.hover_shape and self.hover_shape.type != "display":
|
||||||
if self.hover_shape.type == 'bone' and self.hover_shape.bone:
|
if self.hover_shape.type == "bone" and self.hover_shape.bone:
|
||||||
self.tooltip = self.hover_shape.bone.name
|
self.tooltip = self.hover_shape.bone.name
|
||||||
else:
|
else:
|
||||||
self.tooltip = self.hover_shape.tooltip
|
self.tooltip = self.hover_shape.tooltip
|
||||||
self.tooltip_shape = self.hover_shape
|
self.tooltip_shape = self.hover_shape
|
||||||
else:
|
else:
|
||||||
return self.clear_tooltip()
|
return self.clear_tooltip()
|
||||||
|
|
||||||
|
|
||||||
self.tooltip_mouse = self.mouse
|
self.tooltip_mouse = self.mouse
|
||||||
|
|
||||||
self.timer.cancel()
|
self.timer.cancel()
|
||||||
|
|
||||||
#print(self.tooltip)
|
# print(self.tooltip)
|
||||||
|
|
||||||
self.region.tag_redraw()
|
self.region.tag_redraw()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rect(self):
|
def rect(self):
|
||||||
return bounding_rect([co - Vector(p.translation) for p in self.pickers for co in p.rect])
|
return bounding_rect(
|
||||||
|
[co - Vector(p.translation) for p in self.pickers for co in p.rect]
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def center(self):
|
def center(self):
|
||||||
@ -710,23 +743,27 @@ class PickerGroup:
|
|||||||
return center
|
return center
|
||||||
|
|
||||||
|
|
||||||
def load_picker_data(rig):
|
def load_picker_data(rig: bpy.types.Object):
|
||||||
if 'pickers' in rig.data.rig_picker:
|
if "pickers" in rig.data.rig_picker:
|
||||||
picker_datas = [[s.to_dict() for s in p] for p in rig.data.rig_picker['pickers']]
|
picker_datas = [
|
||||||
|
[s.to_dict() for s in p] for p in rig.data.rig_picker["pickers"]
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
picker_datas = []
|
picker_datas = []
|
||||||
|
|
||||||
for picker in rig.data.rig_picker.sources:
|
for picker in rig.data.rig_picker.sources:
|
||||||
picker_path = Path(bpy.path.abspath(picker.source, library=rig.data.library))
|
picker_path = Path(
|
||||||
|
bpy.path.abspath(picker.source, library=rig.data.library)
|
||||||
|
)
|
||||||
|
|
||||||
if not picker_path.exists():
|
if not picker_path.exists():
|
||||||
print(f'Picker path not exists: {picker_path.resolve()}')
|
print(f"Picker path not exists: {picker_path.resolve()}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print('Load picker from', picker_path.resolve())
|
print("Load picker from", picker_path.resolve())
|
||||||
picker_data = json.loads(picker_path.read_text(encoding='utf-8'))
|
picker_data = json.loads(picker_path.read_text(encoding="utf-8"))
|
||||||
picker_datas.append(picker_data)
|
picker_datas.append(picker_data)
|
||||||
|
|
||||||
PICKERS[rig] = PickerGroup(rig, picker_datas)
|
PICKERS[rig] = PickerGroup(rig, picker_datas)
|
||||||
|
|
||||||
|
|
||||||
@ -736,24 +773,24 @@ def get_picker_path(rig, source, start=None):
|
|||||||
|
|
||||||
|
|
||||||
def pack_picker(rig, start=None):
|
def pack_picker(rig, start=None):
|
||||||
if not 'rig_picker' in rig.data:
|
if not "rig_picker" in rig.data:
|
||||||
return
|
return
|
||||||
|
|
||||||
pickers = []
|
pickers = []
|
||||||
for picker_source in rig.data['rig_picker'].get('sources', []):
|
for picker_source in rig.data["rig_picker"].get("sources", []):
|
||||||
picker_path = get_picker_path(rig, picker_source['source'], start)
|
picker_path = get_picker_path(rig, picker_source["source"], start)
|
||||||
if not picker_path.exists():
|
if not picker_path.exists():
|
||||||
print(f'{picker_path} not exists')
|
print(f"{picker_path} not exists")
|
||||||
continue
|
continue
|
||||||
picker_data = json.loads(picker_path.read_text(encoding='utf-8'))
|
picker_data = json.loads(picker_path.read_text(encoding="utf-8"))
|
||||||
pickers.append(picker_data)
|
pickers.append(picker_data)
|
||||||
|
|
||||||
rig.data['rig_picker']['pickers'] = pickers
|
rig.data["rig_picker"]["pickers"] = pickers
|
||||||
|
|
||||||
|
|
||||||
def unpack_picker(rig):
|
def unpack_picker(rig):
|
||||||
if 'rig_picker' not in rig.data.keys():
|
if "rig_picker" not in rig.data.keys():
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'pickers' in rig.data['rig_picker'].keys():
|
if "pickers" in rig.data["rig_picker"].keys():
|
||||||
del rig.data['rig_picker']['pickers']
|
del rig.data["rig_picker"]["pickers"]
|
||||||
|
|||||||
@ -6,30 +6,29 @@ from .geometry_utils import bound_box_center
|
|||||||
from .addon_utils import get_object_color
|
from .addon_utils import get_object_color
|
||||||
|
|
||||||
|
|
||||||
|
def border_over_shape(border, verts, loops):
|
||||||
def border_over_shape(border,verts,loops):
|
|
||||||
for loop in loops:
|
for loop in loops:
|
||||||
for i,p in enumerate(loop):
|
for i, p in enumerate(loop):
|
||||||
a = Vector(verts[loop[i-1]])
|
a = Vector(verts[loop[i - 1]])
|
||||||
b = Vector(verts[p])
|
b = Vector(verts[p])
|
||||||
|
|
||||||
for j in range(0,4):
|
for j in range(0, 4):
|
||||||
c = border[j-1]
|
c = border[j - 1]
|
||||||
d = border[j]
|
d = border[j]
|
||||||
if intersect_line_line_2d(a,b,c,d):
|
if intersect_line_line_2d(a, b, c, d):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for point in verts:
|
for point in verts:
|
||||||
if point_inside_rect(point,border):
|
if point_inside_rect(point, border):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for point in border:
|
for point in border:
|
||||||
if point_over_shape(point,verts,loops):
|
if point_over_shape(point, verts, loops):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def border_loop(vert, loop):
|
def border_loop(vert, loop):
|
||||||
border_edge =[e for e in vert.link_edges if e.is_rectary]
|
border_edge = [e for e in vert.link_edges if e.is_rectary]
|
||||||
|
|
||||||
if border_edge:
|
if border_edge:
|
||||||
for edge in border_edge:
|
for edge in border_edge:
|
||||||
@ -43,6 +42,7 @@ def border_loop(vert, loop):
|
|||||||
else:
|
else:
|
||||||
return [vert]
|
return [vert]
|
||||||
|
|
||||||
|
|
||||||
def contour_loops(bm, vert_index=0, loops=None, vert_indices=None):
|
def contour_loops(bm, vert_index=0, loops=None, vert_indices=None):
|
||||||
loops = loops or []
|
loops = loops or []
|
||||||
vert_indices = vert_indices or [v.index for v in bm.verts]
|
vert_indices = vert_indices or [v.index for v in bm.verts]
|
||||||
@ -50,7 +50,7 @@ def contour_loops(bm, vert_index=0, loops=None, vert_indices=None):
|
|||||||
bm.verts.ensure_lookup_table()
|
bm.verts.ensure_lookup_table()
|
||||||
|
|
||||||
loop = border_loop(bm.verts[vert_index], [bm.verts[vert_index]])
|
loop = border_loop(bm.verts[vert_index], [bm.verts[vert_index]])
|
||||||
if len(loop) >1:
|
if len(loop) > 1:
|
||||||
loops.append(loop)
|
loops.append(loop)
|
||||||
|
|
||||||
for v in loop:
|
for v in loop:
|
||||||
@ -75,14 +75,13 @@ def get_shape_data(ob, matrix=None, depsgraph=None):
|
|||||||
bm = bmesh.new()
|
bm = bmesh.new()
|
||||||
bm.from_mesh(mesh)
|
bm.from_mesh(mesh)
|
||||||
|
|
||||||
|
|
||||||
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.002)
|
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.dissolve_limit(bm, angle_limit=0.001745, verts=bm.verts, edges=bm.edges)
|
||||||
|
|
||||||
bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
|
bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
|
||||||
bmesh.ops.triangulate(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]
|
edges = [[v.index for v in e.verts] for e in bm.edges if len(e.link_faces) <= 1]
|
||||||
bm.to_mesh(mesh)
|
bm.to_mesh(mesh)
|
||||||
mesh.update()
|
mesh.update()
|
||||||
bm.clear()
|
bm.clear()
|
||||||
@ -96,11 +95,11 @@ def get_shape_data(ob, matrix=None, depsgraph=None):
|
|||||||
points.append([round(co[0], 1), round(co[1], 1)])
|
points.append([round(co[0], 1), round(co[1], 1)])
|
||||||
|
|
||||||
depths += [co[2]]
|
depths += [co[2]]
|
||||||
|
|
||||||
if depths:
|
if depths:
|
||||||
depth = max(depths)
|
depth = max(depths)
|
||||||
else:
|
else:
|
||||||
print(f'{ob.name} has no vertices')
|
print(f"{ob.name} has no vertices")
|
||||||
depth = 0
|
depth = 0
|
||||||
|
|
||||||
for face in mesh.polygons:
|
for face in mesh.polygons:
|
||||||
@ -113,67 +112,70 @@ def get_shape_data(ob, matrix=None, depsgraph=None):
|
|||||||
color = [0.5, 0.5, 0.5]
|
color = [0.5, 0.5, 0.5]
|
||||||
|
|
||||||
shape = {
|
shape = {
|
||||||
'source_name': ob.name,
|
"source_name": ob.name,
|
||||||
'tooltip': ob.rig_picker.name,
|
"tooltip": ob.rig_picker.name,
|
||||||
'depth': depth,
|
"depth": depth,
|
||||||
'points': points,
|
"points": points,
|
||||||
'polygons': polygons,
|
"polygons": polygons,
|
||||||
'edges': edges,
|
"edges": edges,
|
||||||
'color': color,
|
"color": color,
|
||||||
'type': ob.rig_picker.shape_type
|
"type": ob.rig_picker.shape_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
if shape['type'] =='OPERATOR':
|
if shape["type"] == "OPERATOR":
|
||||||
shape['operator'] = ob.rig_picker.operator
|
shape["operator"] = ob.rig_picker.operator
|
||||||
shape['shortcut'] = ob.rig_picker.shortcut
|
shape["shortcut"] = ob.rig_picker.shortcut
|
||||||
|
|
||||||
|
elif shape["type"] == "BONE":
|
||||||
|
shape["bone"] = ob.rig_picker.name
|
||||||
|
|
||||||
elif shape['type'] =='BONE':
|
|
||||||
shape['bone'] = ob.rig_picker.name
|
|
||||||
|
|
||||||
eval_ob.to_mesh_clear()
|
eval_ob.to_mesh_clear()
|
||||||
|
|
||||||
return shape
|
return shape
|
||||||
|
|
||||||
|
|
||||||
def get_picker_data(collection):
|
def get_picker_data(collection):
|
||||||
picker_data = []
|
picker_data = []
|
||||||
|
|
||||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
canvas = collection.rig_picker.canvas
|
canvas = collection.rig_picker.canvas
|
||||||
|
|
||||||
if canvas.type == 'CURVE':
|
if canvas.type == "CURVE":
|
||||||
canvas_points = canvas.data.splines[0].points
|
canvas_points = canvas.data.splines[0].points
|
||||||
else:
|
else:
|
||||||
canvas_points = canvas.data.vertices
|
canvas_points = canvas.data.vertices
|
||||||
|
|
||||||
canvas_coords = [canvas.matrix_world@Vector((p.co)) for p in canvas_points]
|
canvas_coords = [canvas.matrix_world @ Vector((p.co)) for p in canvas_points]
|
||||||
|
|
||||||
height = abs(max(co.y for co in canvas_coords) - min(co.y for co in canvas_coords))
|
height = abs(max(co.y for co in canvas_coords) - min(co.y for co in canvas_coords))
|
||||||
width = abs(max(co.x for co in canvas_coords) - min(co.x for co in canvas_coords))
|
width = abs(max(co.x for co in canvas_coords) - min(co.x for co in canvas_coords))
|
||||||
|
|
||||||
center = sum(canvas_coords, Vector()) / len(canvas_coords)
|
center = sum(canvas_coords, Vector()) / len(canvas_coords)
|
||||||
scale = 2048 / max(height, width)# Reference height for the canvas
|
scale = 2048 / max(height, width) # Reference height for the canvas
|
||||||
|
|
||||||
matrix = Matrix.Translation(-center)
|
matrix = Matrix.Translation(-center)
|
||||||
matrix = Matrix.Scale(scale, 4) @ matrix
|
matrix = Matrix.Scale(scale, 4) @ matrix
|
||||||
|
|
||||||
#sorted by their z axes
|
# sorted by their z axes
|
||||||
for ob in collection.all_objects:
|
for ob in collection.all_objects:
|
||||||
if ob.instance_collection:
|
if ob.instance_collection:
|
||||||
for shape in ob.instance_collection.all_objects:
|
for shape in ob.instance_collection.all_objects:
|
||||||
picker_data.append(get_shape_data(shape, matrix=matrix@ob.matrix_world, depsgraph=depsgraph))
|
picker_data.append(
|
||||||
|
get_shape_data(
|
||||||
elif ob.type in ('MESH', 'CURVE', 'FONT'):
|
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))
|
picker_data.append(get_shape_data(ob, matrix=matrix, depsgraph=depsgraph))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
#print(f'{ob.name} of type {ob.type} not supported')
|
# print(f'{ob.name} of type {ob.type} not supported')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
picker_data.sort(key=lambda x : x['depth'])
|
picker_data.sort(key=lambda x: x["depth"])
|
||||||
|
|
||||||
#print(picker_datas)
|
# print(picker_datas)
|
||||||
|
|
||||||
return picker_data
|
return picker_data
|
||||||
#rig.data.rig_picker['shapes'] = picker_datas
|
# rig.data.rig_picker['shapes'] = picker_datas
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import gpu
|
import gpu
|
||||||
from gpu_extras.batch import batch_for_shader
|
from gpu_extras.batch import batch_for_shader
|
||||||
@ -20,12 +19,13 @@ def draw_rect_2d(position, width, height, color):
|
|||||||
:arg height: Height of the rect.
|
:arg height: Height of the rect.
|
||||||
:type height: float
|
:type height: float
|
||||||
"""
|
"""
|
||||||
|
|
||||||
coords = ((0, 0), (1, 0), (1, 1), (0, 1))
|
coords = ((0, 0), (1, 0), (1, 1), (0, 1))
|
||||||
|
|
||||||
shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||||
batch = batch_for_shader(
|
batch = batch_for_shader(
|
||||||
shader, 'TRI_FAN',
|
shader,
|
||||||
|
"TRI_FAN",
|
||||||
{"pos": coords},
|
{"pos": coords},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ def draw_rect_2d(position, width, height, color):
|
|||||||
def draw_callback_view():
|
def draw_callback_view():
|
||||||
space_data = bpy.context.space_data
|
space_data = bpy.context.space_data
|
||||||
|
|
||||||
if not space_data or not space_data.tree_type == 'RigPickerTree':
|
if not space_data or not space_data.tree_type == "RigPickerTree":
|
||||||
return
|
return
|
||||||
|
|
||||||
# Use the pin to know if this is the first time this picker window in created to hide the n panel
|
# Use the pin to know if this is the first time this picker window in created to hide the n panel
|
||||||
@ -49,19 +49,19 @@ def draw_callback_view():
|
|||||||
space_data.show_region_ui = False
|
space_data.show_region_ui = False
|
||||||
|
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
if not ob or ob.type !='ARMATURE' or not ob.data.rig_picker.sources:
|
if not ob or ob.type != "ARMATURE" or not ob.data.rig_picker.sources:
|
||||||
return
|
return
|
||||||
|
|
||||||
if ob not in PICKERS:
|
if ob not in PICKERS:
|
||||||
load_picker_data(ob)
|
load_picker_data(ob)
|
||||||
|
|
||||||
picker_group = PICKERS[ob]
|
picker_group = PICKERS[ob]
|
||||||
picker_group.draw()
|
picker_group.draw()
|
||||||
|
|
||||||
|
|
||||||
def draw_callback_px():
|
def draw_callback_px():
|
||||||
sp = bpy.context.space_data
|
sp = bpy.context.space_data
|
||||||
if not sp.tree_type == 'RigPickerTree':
|
if not sp.tree_type == "RigPickerTree":
|
||||||
return
|
return
|
||||||
|
|
||||||
ob = bpy.context.object
|
ob = bpy.context.object
|
||||||
@ -74,37 +74,36 @@ def draw_callback_px():
|
|||||||
text = picker_group.tooltip
|
text = picker_group.tooltip
|
||||||
ui_scale = bpy.context.preferences.system.ui_scale
|
ui_scale = bpy.context.preferences.system.ui_scale
|
||||||
|
|
||||||
#print('Draw text', text)
|
# print('Draw text', text)
|
||||||
font_id = 0
|
font_id = 0
|
||||||
blf.size(font_id, int(13 * ui_scale))
|
blf.size(font_id, int(13 * ui_scale))
|
||||||
|
|
||||||
margins = [12, 5]
|
margins = [12, 5]
|
||||||
text_size = blf.dimensions(font_id, text)
|
text_size = blf.dimensions(font_id, text)
|
||||||
text_pos = (region.width - text_size[0]-margins[0], margins[1])
|
text_pos = (region.width - text_size[0] - margins[0], margins[1])
|
||||||
|
|
||||||
bg_pos = (text_pos[0] - margins[0], text_pos[1] - margins[1]-1)
|
bg_pos = (text_pos[0] - margins[0], text_pos[1] - margins[1] - 1)
|
||||||
bg_size = (text_size[0] + 2*margins[0], text_size[1] + 2*margins[1])
|
bg_size = (text_size[0] + 2 * margins[0], text_size[1] + 2 * margins[1])
|
||||||
|
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set("ALPHA")
|
||||||
draw_rect_2d(bg_pos, *bg_size, (0.1, 0.1, 0.1, 0.66))
|
draw_rect_2d(bg_pos, *bg_size, (0.1, 0.1, 0.1, 0.66))
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set("NONE")
|
||||||
|
|
||||||
|
# blf.dimensions(font_id, text)
|
||||||
#blf.dimensions(font_id, text)
|
|
||||||
blf.enable(font_id, blf.SHADOW)
|
blf.enable(font_id, blf.SHADOW)
|
||||||
|
|
||||||
|
|
||||||
# BLF drawing routine
|
# BLF drawing routine
|
||||||
blf.position(font_id, round(text_pos[0]), round(text_pos[1]), 0)
|
blf.position(font_id, round(text_pos[0]), round(text_pos[1]), 0)
|
||||||
blf.color(font_id, 0.85, 0.85, 0.85, 1)
|
blf.color(font_id, 0.85, 0.85, 0.85, 1)
|
||||||
|
|
||||||
blf.shadow(font_id , 5, 0.0, 0.0, 0.0, 1)
|
blf.shadow(font_id, 5, 0.0, 0.0, 0.0, 1)
|
||||||
blf.shadow_offset(font_id, 2, -2)
|
blf.shadow_offset(font_id, 2, -2)
|
||||||
|
|
||||||
blf.draw(font_id, text)
|
blf.draw(font_id, text)
|
||||||
|
|
||||||
blf.disable(font_id, blf.SHADOW)
|
blf.disable(font_id, blf.SHADOW)
|
||||||
|
|
||||||
|
|
||||||
handle_view = None
|
handle_view = None
|
||||||
handle_pixel = None
|
handle_pixel = None
|
||||||
|
|
||||||
@ -113,15 +112,20 @@ def register():
|
|||||||
global handle_view
|
global handle_view
|
||||||
global handle_pixel
|
global handle_pixel
|
||||||
|
|
||||||
handle_view = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_view, (), 'WINDOW', 'POST_VIEW')
|
handle_view = bpy.types.SpaceNodeEditor.draw_handler_add(
|
||||||
handle_pixel = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_px, (), 'WINDOW', 'POST_PIXEL')
|
draw_callback_view, (), "WINDOW", "POST_VIEW"
|
||||||
|
)
|
||||||
|
handle_pixel = bpy.types.SpaceNodeEditor.draw_handler_add(
|
||||||
|
draw_callback_px, (), "WINDOW", "POST_PIXEL"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
global handle_view
|
global handle_view
|
||||||
global handle_pixel
|
global handle_pixel
|
||||||
|
|
||||||
bpy.types.SpaceNodeEditor.draw_handler_remove(handle_view, 'WINDOW')
|
bpy.types.SpaceNodeEditor.draw_handler_remove(handle_view, "WINDOW")
|
||||||
bpy.types.SpaceNodeEditor.draw_handler_remove(handle_pixel, 'WINDOW')
|
bpy.types.SpaceNodeEditor.draw_handler_remove(handle_pixel, "WINDOW")
|
||||||
|
|
||||||
handle_view = None
|
handle_view = None
|
||||||
handle_pixel = None
|
handle_pixel = None
|
||||||
|
|||||||
59
gizmo.py
59
gizmo.py
@ -1,16 +1,13 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from bpy.props import (IntProperty, EnumProperty, BoolProperty)
|
from bpy.props import IntProperty, EnumProperty, BoolProperty
|
||||||
from bpy.types import (AddonPreferences, GizmoGroup, Operator, Gizmo)
|
from bpy.types import AddonPreferences, GizmoGroup, Operator, Gizmo
|
||||||
|
|
||||||
from mathutils import Vector, Matrix, Euler
|
from mathutils import Vector, Matrix, Euler
|
||||||
from .constants import PICKERS
|
from .constants import PICKERS
|
||||||
from .core.picker import Picker
|
from .core.picker import Picker
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
class RP_OT_simple_operator(bpy.types.Operator):
|
class RP_OT_simple_operator(bpy.types.Operator):
|
||||||
"""Tooltip"""
|
"""Tooltip"""
|
||||||
@ -40,10 +37,6 @@ class RP_OT_simple_operator(bpy.types.Operator):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RP_GT_gizmo(Gizmo):
|
class RP_GT_gizmo(Gizmo):
|
||||||
|
|
||||||
def test_select(self, context, location):
|
def test_select(self, context, location):
|
||||||
@ -55,27 +48,25 @@ class RP_GT_gizmo(Gizmo):
|
|||||||
|
|
||||||
picker.move_event(location)
|
picker.move_event(location)
|
||||||
|
|
||||||
#if bpy.app.timers.is_registered(tooltip):
|
# if bpy.app.timers.is_registered(tooltip):
|
||||||
# bpy.app.timers.unregister(tooltip)
|
# bpy.app.timers.unregister(tooltip)
|
||||||
#context.region.tag_redraw()
|
# context.region.tag_redraw()
|
||||||
|
|
||||||
#picker.tooltip_event(event='START')
|
|
||||||
#bpy.app.timers.register(partial(tooltip, context.region), first_interval=1)
|
|
||||||
|
|
||||||
#print(location)
|
|
||||||
|
|
||||||
|
# picker.tooltip_event(event='START')
|
||||||
|
# bpy.app.timers.register(partial(tooltip, context.region), first_interval=1)
|
||||||
|
|
||||||
|
# print(location)
|
||||||
|
|
||||||
context.region.tag_redraw()
|
context.region.tag_redraw()
|
||||||
|
|
||||||
#print(location)
|
# print(location)
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
return
|
return
|
||||||
'''
|
|
||||||
|
"""
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
print(f'invoke: type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
|
print(f'invoke: type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
@ -88,39 +79,35 @@ class RP_GT_gizmo(Gizmo):
|
|||||||
def exit(self, context, cancel):
|
def exit(self, context, cancel):
|
||||||
print('EXIT')
|
print('EXIT')
|
||||||
|
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RP_GT_gizmogroup(GizmoGroup):
|
class RP_GT_gizmogroup(GizmoGroup):
|
||||||
""" test gizmo button 2d """
|
"""test gizmo button 2d"""
|
||||||
|
|
||||||
bl_idname = "view3d.gizmo_button_2d"
|
bl_idname = "view3d.gizmo_button_2d"
|
||||||
bl_label = "Test button 2d"
|
bl_label = "Test button 2d"
|
||||||
bl_space_type = 'NODE_EDITOR'
|
bl_space_type = "NODE_EDITOR"
|
||||||
bl_region_type = 'WINDOW'
|
bl_region_type = "WINDOW"
|
||||||
bl_options = {'PERSISTENT'}
|
bl_options = {"PERSISTENT"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.space_data.tree_type == 'RigPickerTree'
|
return context.space_data.tree_type == "RigPickerTree"
|
||||||
|
|
||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
self.gizmo = self.gizmos.new("RP_GT_gizmo")
|
self.gizmo = self.gizmos.new("RP_GT_gizmo")
|
||||||
|
|
||||||
|
|
||||||
|
classes = (RP_GT_gizmo, RP_GT_gizmogroup)
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
|
||||||
RP_GT_gizmo,
|
|
||||||
RP_GT_gizmogroup
|
|
||||||
)
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
|
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|||||||
@ -1,20 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
from . import material
|
from . import material
|
||||||
from . import picker
|
from . import picker
|
||||||
from . import shape
|
from . import shape
|
||||||
|
|
||||||
|
|
||||||
modules = (
|
modules = (material, picker, shape)
|
||||||
material,
|
|
||||||
picker,
|
|
||||||
shape
|
|
||||||
)
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for mod in modules:
|
for mod in modules:
|
||||||
mod.register()
|
mod.register()
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for mod in reversed(modules):
|
for mod in reversed(modules):
|
||||||
mod.unregister()
|
mod.unregister()
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy_extras import view3d_utils
|
from bpy_extras import view3d_utils
|
||||||
|
|
||||||
@ -6,56 +5,55 @@ from bpy_extras import view3d_utils
|
|||||||
class RP_OT_add_material(bpy.types.Operator):
|
class RP_OT_add_material(bpy.types.Operator):
|
||||||
bl_label = "Add Ui Material"
|
bl_label = "Add Ui Material"
|
||||||
bl_idname = "rigpicker.add_mat"
|
bl_idname = "rigpicker.add_mat"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
|
|
||||||
mat = bpy.data.materials.new('UI')
|
mat = bpy.data.materials.new("UI")
|
||||||
mat.use_nodes = True
|
mat.use_nodes = True
|
||||||
|
|
||||||
for node in mat.node_tree.nodes:
|
for node in mat.node_tree.nodes:
|
||||||
if node.type == 'OUTPUT_MATERIAL':
|
if node.type == "OUTPUT_MATERIAL":
|
||||||
mat_output = node
|
mat_output = node
|
||||||
else:
|
else:
|
||||||
mat.node_tree.nodes.remove(node)
|
mat.node_tree.nodes.remove(node)
|
||||||
|
|
||||||
emission = mat.node_tree.nodes.new('ShaderNodeEmission')
|
emission = mat.node_tree.nodes.new("ShaderNodeEmission")
|
||||||
mat.node_tree.links.new(emission.outputs[0],mat_output.inputs[0])
|
mat.node_tree.links.new(emission.outputs[0], mat_output.inputs[0])
|
||||||
|
|
||||||
|
|
||||||
if not context.object.data.materials:
|
if not context.object.data.materials:
|
||||||
context.object.data.materials.append(mat)
|
context.object.data.materials.append(mat)
|
||||||
else:
|
else:
|
||||||
context.object.material_slots[0].material = mat
|
context.object.material_slots[0].material = mat
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_remove_material(bpy.types.Operator):
|
class RP_OT_remove_material(bpy.types.Operator):
|
||||||
bl_label = "Remove Ui Material"
|
bl_label = "Remove Ui Material"
|
||||||
bl_idname = "rigpicker.remove_mat"
|
bl_idname = "rigpicker.remove_mat"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
#print(self.shape_type)
|
# print(self.shape_type)
|
||||||
for mat in context.object.data.materials:
|
for mat in context.object.data.materials:
|
||||||
bpy.data.materials.remove(mat)
|
bpy.data.materials.remove(mat)
|
||||||
context.area.tag_redraw()
|
context.area.tag_redraw()
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_eyedropper_material(bpy.types.Operator):
|
class RP_OT_eyedropper_material(bpy.types.Operator):
|
||||||
"""Tooltip"""
|
"""Tooltip"""
|
||||||
|
|
||||||
bl_idname = "rigpicker.eyedropper_mat"
|
bl_idname = "rigpicker.eyedropper_mat"
|
||||||
bl_label = "Eye Dropper mat"
|
bl_label = "Eye Dropper mat"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
#first_mouse_x = IntProperty()
|
|
||||||
#first_value = FloatProperty()
|
|
||||||
|
|
||||||
|
# first_mouse_x = IntProperty()
|
||||||
|
# first_value = FloatProperty()
|
||||||
|
|
||||||
def modal(self, context, event):
|
def modal(self, context, event):
|
||||||
context.area.tag_redraw()
|
context.area.tag_redraw()
|
||||||
@ -66,7 +64,7 @@ class RP_OT_eyedropper_material(bpy.types.Operator):
|
|||||||
region = context.region
|
region = context.region
|
||||||
rv3d = context.region_data
|
rv3d = context.region_data
|
||||||
|
|
||||||
if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
|
if event.type == "LEFTMOUSE" and event.value == "RELEASE":
|
||||||
self.mouse = event.mouse_region_x, event.mouse_region_y
|
self.mouse = event.mouse_region_x, event.mouse_region_y
|
||||||
|
|
||||||
dg = context.evaluated_depsgraph_get()
|
dg = context.evaluated_depsgraph_get()
|
||||||
@ -76,47 +74,48 @@ class RP_OT_eyedropper_material(bpy.types.Operator):
|
|||||||
|
|
||||||
raycast = scene.ray_cast(dg, ray_origin, view_vector)
|
raycast = scene.ray_cast(dg, ray_origin, view_vector)
|
||||||
|
|
||||||
if raycast[0]==True:
|
if raycast[0] == True:
|
||||||
ob = raycast[4]
|
ob = raycast[4]
|
||||||
|
|
||||||
if ob.data.materials:
|
if ob.data.materials:
|
||||||
mat = ob.data.materials[0]
|
mat = ob.data.materials[0]
|
||||||
for shape in [o for o in context.selected_objects if o.type in ('MESH','CURVE','FONT')]:
|
for shape in [
|
||||||
|
o
|
||||||
|
for o in context.selected_objects
|
||||||
|
if o.type in ("MESH", "CURVE", "FONT")
|
||||||
|
]:
|
||||||
if not shape.data.materials:
|
if not shape.data.materials:
|
||||||
shape.data.materials.append(mat)
|
shape.data.materials.append(mat)
|
||||||
else:
|
else:
|
||||||
shape.material_slots[0].material = mat
|
shape.material_slots[0].material = mat
|
||||||
|
|
||||||
|
# context.space_data.draw_handler_remove(self._handle, 'WINDOW')
|
||||||
#context.space_data.draw_handler_remove(self._handle, 'WINDOW')
|
|
||||||
|
|
||||||
context.window.cursor_modal_restore()
|
context.window.cursor_modal_restore()
|
||||||
|
|
||||||
for ob in self.temp_ob:
|
for ob in self.temp_ob:
|
||||||
bpy.data.objects.remove(ob)
|
bpy.data.objects.remove(ob)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
# return {'FINISHED'}
|
||||||
|
|
||||||
#return {'FINISHED'}
|
elif event.type in {"RIGHTMOUSE", "ESC"}:
|
||||||
|
# context.object.location.x = self.first_value
|
||||||
elif event.type in {'RIGHTMOUSE', 'ESC'}:
|
|
||||||
#context.object.location.x = self.first_value
|
|
||||||
context.window.cursor_modal_restore()
|
context.window.cursor_modal_restore()
|
||||||
|
|
||||||
for ob in self.temp_ob:
|
for ob in self.temp_ob:
|
||||||
bpy.data.objects.remove(ob)
|
bpy.data.objects.remove(ob)
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
|
||||||
|
|
||||||
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
#self.local_cursor = tuple(context.space_data.cursor.location)
|
# self.local_cursor = tuple(context.space_data.cursor.location)
|
||||||
#self.cursor = tuple(context.scene.cursor.location)
|
# self.cursor = tuple(context.scene.cursor.location)
|
||||||
|
|
||||||
curves =[o for o in context.visible_objects if o.type in ('CURVE', 'FONT')]
|
curves = [o for o in context.visible_objects if o.type in ("CURVE", "FONT")]
|
||||||
|
|
||||||
self.temp_ob = []
|
self.temp_ob = []
|
||||||
|
|
||||||
@ -124,17 +123,17 @@ class RP_OT_eyedropper_material(bpy.types.Operator):
|
|||||||
|
|
||||||
for c in curves:
|
for c in curves:
|
||||||
mesh = bpy.data.meshes.new_from_object(c.evaluated_get(dg))
|
mesh = bpy.data.meshes.new_from_object(c.evaluated_get(dg))
|
||||||
copy = bpy.data.objects.new(c.name+'_tmp', mesh)
|
copy = bpy.data.objects.new(c.name + "_tmp", mesh)
|
||||||
copy.matrix_world = c.matrix_world
|
copy.matrix_world = c.matrix_world
|
||||||
for mat in c.data.materials:
|
for mat in c.data.materials:
|
||||||
copy.data.materials.append(mat)
|
copy.data.materials.append(mat)
|
||||||
scene.collection.objects.link(copy)
|
scene.collection.objects.link(copy)
|
||||||
self.temp_ob.append(copy)
|
self.temp_ob.append(copy)
|
||||||
#args = (self,context)
|
# args = (self,context)
|
||||||
#self._handle = context.space_data.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
|
# self._handle = context.space_data.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
|
||||||
context.window_manager.modal_handler_add(self)
|
context.window_manager.modal_handler_add(self)
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
@ -143,4 +142,4 @@ classes = (
|
|||||||
RP_OT_eyedropper_material,
|
RP_OT_eyedropper_material,
|
||||||
)
|
)
|
||||||
|
|
||||||
register, unregister = bpy.utils.register_classes_factory(classes)
|
register, unregister = bpy.utils.register_classes_factory(classes)
|
||||||
|
|||||||
@ -6,10 +6,11 @@ from ..core.addon_utils import get_picker_collection
|
|||||||
from ..core.bl_utils import get_view_3d_override, split_path, eval_attr
|
from ..core.bl_utils import get_view_3d_override, split_path, eval_attr
|
||||||
from ..core.geometry_utils import bounding_rect
|
from ..core.geometry_utils import bounding_rect
|
||||||
from ..core.picker import get_picker_path, pack_picker, unpack_picker, load_picker_data
|
from ..core.picker import get_picker_path, pack_picker, unpack_picker, load_picker_data
|
||||||
#from .func_bgl import draw_callback_px
|
|
||||||
#from .func_bgl import select_bone
|
# from .func_bgl import draw_callback_px
|
||||||
#from core.picker import *
|
# from .func_bgl import select_bone
|
||||||
#from .utils import is_over_region
|
# from core.picker import *
|
||||||
|
# from .utils import is_over_region
|
||||||
import gpu
|
import gpu
|
||||||
from mathutils import Vector, Euler, Matrix
|
from mathutils import Vector, Euler, Matrix
|
||||||
from gpu_extras.batch import batch_for_shader
|
from gpu_extras.batch import batch_for_shader
|
||||||
@ -18,34 +19,36 @@ import json
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def is_picker_space(space_data=None):
|
def is_picker_space(space_data=None):
|
||||||
if not space_data:
|
if not space_data:
|
||||||
space_data = bpy.context.space_data
|
space_data = bpy.context.space_data
|
||||||
if space_data and (space_data.type == 'NODE_EDITOR' and space_data.tree_type == 'RigPickerTree'):
|
if space_data and (
|
||||||
|
space_data.type == "NODE_EDITOR" and space_data.tree_type == "RigPickerTree"
|
||||||
|
):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_box_select(Operator):
|
class RP_OT_box_select(Operator):
|
||||||
"""Box Select bones in the picker view"""
|
"""Box Select bones in the picker view"""
|
||||||
|
|
||||||
bl_idname = "node.rp_box_select"
|
bl_idname = "node.rp_box_select"
|
||||||
bl_label = "Picker Box Select"
|
bl_label = "Picker Box Select"
|
||||||
|
|
||||||
mode: EnumProperty(items=[(i, i.title(), '') for i in ('SET', 'EXTEND', 'SUBSTRACT')])
|
mode: EnumProperty(
|
||||||
|
items=[(i, i.title(), "") for i in ("SET", "EXTEND", "SUBSTRACT")]
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
if not is_picker_space(context.space_data):
|
if not is_picker_space(context.space_data):
|
||||||
return
|
return
|
||||||
|
|
||||||
ob = context.object
|
ob = context.object
|
||||||
return ob and ob in PICKERS
|
return ob and ob in PICKERS
|
||||||
|
|
||||||
'''
|
"""
|
||||||
def mode_from_event(self, event):
|
def mode_from_event(self, event):
|
||||||
if event.alt:
|
if event.alt:
|
||||||
return 'SUBSTRACT'
|
return 'SUBSTRACT'
|
||||||
@ -53,17 +56,17 @@ class RP_OT_box_select(Operator):
|
|||||||
return 'EXTEND'
|
return 'EXTEND'
|
||||||
else:
|
else:
|
||||||
return 'SET'
|
return 'SET'
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def draw_callback(self):
|
def draw_callback(self):
|
||||||
#print('draw callback border')
|
# print('draw callback border')
|
||||||
if not self.draw_border:
|
if not self.draw_border:
|
||||||
return
|
return
|
||||||
|
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set("ALPHA")
|
||||||
|
|
||||||
|
# print('DRAW BORDER')
|
||||||
|
|
||||||
#print('DRAW BORDER')
|
|
||||||
|
|
||||||
self.color_shader.bind()
|
self.color_shader.bind()
|
||||||
self.color_shader.uniform_float("color", self.bg_color)
|
self.color_shader.uniform_float("color", self.bg_color)
|
||||||
self.bg_batch.draw(self.color_shader)
|
self.bg_batch.draw(self.color_shader)
|
||||||
@ -75,93 +78,100 @@ class RP_OT_box_select(Operator):
|
|||||||
self.dash_shader.uniform_float("viewMatrix", matrix)
|
self.dash_shader.uniform_float("viewMatrix", matrix)
|
||||||
self.dash_shader.uniform_float("dashSize", 5)
|
self.dash_shader.uniform_float("dashSize", 5)
|
||||||
self.dash_shader.uniform_float("gapSize", 4)
|
self.dash_shader.uniform_float("gapSize", 4)
|
||||||
|
|
||||||
self.contour_batch.draw(self.dash_shader)
|
self.contour_batch.draw(self.dash_shader)
|
||||||
|
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set("NONE")
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
#print(f'invoke: type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
|
# print(f'invoke: type={event.type}, value={event.value}, ctrl={event.ctrl}, shift={event.shift}, alt={event.alt}')
|
||||||
|
|
||||||
if context.object.mode != 'POSE':
|
if context.object.mode != "POSE":
|
||||||
bpy.ops.object.posemode_toggle()
|
bpy.ops.object.posemode_toggle()
|
||||||
|
|
||||||
self.timer = None
|
self.timer = None
|
||||||
#self.mode = self.mode_from_event(event)
|
# self.mode = self.mode_from_event(event)
|
||||||
#self.invoke_event = event.copy()
|
# self.invoke_event = event.copy()
|
||||||
self.region = context.region
|
self.region = context.region
|
||||||
self.draw_border = False
|
self.draw_border = False
|
||||||
|
|
||||||
self.picker = PICKERS[context.object]
|
self.picker = PICKERS[context.object]
|
||||||
|
|
||||||
self.start_mouse = event.mouse_region_x, event.mouse_region_y
|
self.start_mouse = event.mouse_region_x, event.mouse_region_y
|
||||||
#self.shader = line_strip_shader
|
# self.shader = line_strip_shader
|
||||||
self.border_color = [1, 1, 1, 1]
|
self.border_color = [1, 1, 1, 1]
|
||||||
self.bg_color = [1, 1, 1, 0.05]
|
self.bg_color = [1, 1, 1, 0.05]
|
||||||
|
|
||||||
#args = (self, context)
|
# args = (self, context)
|
||||||
self.color_shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
self.color_shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||||
self.dash_shader = SHADERS['dashed_line']
|
self.dash_shader = SHADERS["dashed_line"]
|
||||||
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(self.draw_callback, (), 'WINDOW', 'POST_PIXEL')
|
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(
|
||||||
|
self.draw_callback, (), "WINDOW", "POST_PIXEL"
|
||||||
|
)
|
||||||
|
|
||||||
context.window_manager.modal_handler_add(self)
|
context.window_manager.modal_handler_add(self)
|
||||||
|
|
||||||
self.picker.press_event(self.mode)
|
self.picker.press_event(self.mode)
|
||||||
self.region.tag_redraw()
|
self.region.tag_redraw()
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
def modal(self, context, event):
|
|
||||||
|
|
||||||
|
def modal(self, context, event):
|
||||||
self.mouse = event.mouse_region_x, event.mouse_region_y
|
self.mouse = event.mouse_region_x, event.mouse_region_y
|
||||||
|
|
||||||
self.border = bounding_rect((self.start_mouse, self.mouse))
|
self.border = bounding_rect((self.start_mouse, self.mouse))
|
||||||
|
|
||||||
self.bg_batch = batch_for_shader(self.color_shader, 'TRI_FAN', {"pos": self.border})
|
self.bg_batch = batch_for_shader(
|
||||||
self.contour_batch = batch_for_shader(self.dash_shader, 'LINE_LOOP', {"pos": self.border})
|
self.color_shader, "TRI_FAN", {"pos": self.border}
|
||||||
|
)
|
||||||
|
self.contour_batch = batch_for_shader(
|
||||||
|
self.dash_shader, "LINE_LOOP", {"pos": self.border}
|
||||||
|
)
|
||||||
|
|
||||||
self.draw_border = True
|
self.draw_border = True
|
||||||
|
|
||||||
self.region.tag_redraw()
|
self.region.tag_redraw()
|
||||||
|
|
||||||
if event.value == 'RELEASE':
|
if event.value == "RELEASE":
|
||||||
return self.release_event(context)
|
return self.release_event(context)
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
def release_event(self, context):
|
def release_event(self, context):
|
||||||
|
|
||||||
if get_picker_collection():
|
if get_picker_collection():
|
||||||
self.picker.assign_bone_event()
|
self.picker.assign_bone_event()
|
||||||
|
|
||||||
elif (self.start_mouse[0] != self.mouse[0] or self.start_mouse[1] != self.mouse[1]):
|
elif (
|
||||||
|
self.start_mouse[0] != self.mouse[0] or self.start_mouse[1] != self.mouse[1]
|
||||||
|
):
|
||||||
self.picker.border_select(self.border, self.mode)
|
self.picker.border_select(self.border, self.mode)
|
||||||
else:
|
else:
|
||||||
self.picker.move_event(self.mouse)
|
self.picker.move_event(self.mouse)
|
||||||
self.picker.release_event(self.mode)
|
self.picker.release_event(self.mode)
|
||||||
|
|
||||||
bpy.ops.ed.undo_push(message="Box Select")
|
bpy.ops.ed.undo_push(message="Box Select")
|
||||||
|
|
||||||
return self.exit(context)
|
return self.exit(context)
|
||||||
|
|
||||||
def exit(self, context):
|
def exit(self, context):
|
||||||
bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
|
bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, "WINDOW")
|
||||||
context.region.tag_redraw()
|
context.region.tag_redraw()
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_picker_transform(Operator):
|
class RP_OT_picker_transform(Operator):
|
||||||
"""Transform Bones in the picker view"""
|
"""Transform Bones in the picker view"""
|
||||||
|
|
||||||
bl_idname = "node.picker_transform"
|
bl_idname = "node.picker_transform"
|
||||||
bl_label = "Transform Bone in Picker View"
|
bl_label = "Transform Bone in Picker View"
|
||||||
|
|
||||||
mode : EnumProperty(items=[(m, m.title(), '') for m in ('ROTATE', 'SCALE')])
|
mode: EnumProperty(items=[(m, m.title(), "") for m in ("ROTATE", "SCALE")])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_pose_bones and is_picker_space(context.space_data)
|
return context.selected_pose_bones and is_picker_space(context.space_data)
|
||||||
|
|
||||||
'''
|
"""
|
||||||
def draw_callback(self):
|
def draw_callback(self):
|
||||||
gpu.state.blend_set('ALPHA')
|
gpu.state.blend_set('ALPHA')
|
||||||
gpu.state.line_width_set(2)
|
gpu.state.line_width_set(2)
|
||||||
@ -179,18 +189,20 @@ class RP_OT_picker_transform(Operator):
|
|||||||
|
|
||||||
gpu.state.line_width_set(1)
|
gpu.state.line_width_set(1)
|
||||||
gpu.state.blend_set('NONE')
|
gpu.state.blend_set('NONE')
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
self.override = get_view_3d_override()
|
self.override = get_view_3d_override()
|
||||||
|
|
||||||
self.view_center = Vector((int(context.region.width / 2), int(context.region.height / 2)))
|
self.view_center = Vector(
|
||||||
|
(int(context.region.width / 2), int(context.region.height / 2))
|
||||||
|
)
|
||||||
self.mouse_start = Vector((event.mouse_region_x, event.mouse_region_y))
|
self.mouse_start = Vector((event.mouse_region_x, event.mouse_region_y))
|
||||||
self.mouse = Vector((0, 0))
|
self.mouse = Vector((0, 0))
|
||||||
|
|
||||||
transform_type = context.scene.tool_settings.transform_pivot_point
|
transform_type = context.scene.tool_settings.transform_pivot_point
|
||||||
self.center = context.active_pose_bone.matrix.to_translation()
|
self.center = context.active_pose_bone.matrix.to_translation()
|
||||||
if transform_type == 'MEDIAN_POINT':
|
if transform_type == "MEDIAN_POINT":
|
||||||
origins = [b.matrix.to_translation() for b in context.selected_pose_bones]
|
origins = [b.matrix.to_translation() for b in context.selected_pose_bones]
|
||||||
self.center = sum(origins, Vector()) / len(context.selected_pose_bones)
|
self.center = sum(origins, Vector()) / len(context.selected_pose_bones)
|
||||||
# self.bone_data = {}
|
# self.bone_data = {}
|
||||||
@ -198,38 +210,36 @@ class RP_OT_picker_transform(Operator):
|
|||||||
# self.bone_data[bone] = bone.matrix.copy()
|
# self.bone_data[bone] = bone.matrix.copy()
|
||||||
self.bone_data = {b: b.matrix.copy() for b in context.selected_pose_bones}
|
self.bone_data = {b: b.matrix.copy() for b in context.selected_pose_bones}
|
||||||
|
|
||||||
space = self.override['area'].spaces.active
|
space = self.override["area"].spaces.active
|
||||||
|
|
||||||
view_matrix = space.region_3d.view_matrix
|
view_matrix = space.region_3d.view_matrix
|
||||||
if space.region_3d.view_perspective == 'CAMERA':
|
if space.region_3d.view_perspective == "CAMERA":
|
||||||
view_matrix = context.scene.camera.matrix_world
|
view_matrix = context.scene.camera.matrix_world
|
||||||
|
|
||||||
context.window.cursor_modal_set('MOVE_X')
|
context.window.cursor_modal_set("MOVE_X")
|
||||||
self.view_vector = Vector((0, 0, 1))
|
self.view_vector = Vector((0, 0, 1))
|
||||||
if self.mode == 'ROTATE':
|
if self.mode == "ROTATE":
|
||||||
self.view_vector.rotate(view_matrix)
|
self.view_vector.rotate(view_matrix)
|
||||||
|
|
||||||
|
|
||||||
elif self.mode == 'SCALE':
|
elif self.mode == "SCALE":
|
||||||
self.view_vector = Vector((0, 0, 0))
|
self.view_vector = Vector((0, 0, 0))
|
||||||
|
|
||||||
self.transform_type = "VIEW"
|
self.transform_type = "VIEW"
|
||||||
self.transform_types = ["VIEW", 'GLOBAL', 'LOCAL']
|
self.transform_types = ["VIEW", "GLOBAL", "LOCAL"]
|
||||||
if context.scene.transform_orientation_slots[0].type == 'LOCAL':
|
if context.scene.transform_orientation_slots[0].type == "LOCAL":
|
||||||
self.transform_types = ["VIEW", 'LOCAL', 'GLOBAL']
|
self.transform_types = ["VIEW", "LOCAL", "GLOBAL"]
|
||||||
|
|
||||||
self.transform_orientation = context.scene.transform_orientation_slots[0].type
|
self.transform_orientation = context.scene.transform_orientation_slots[0].type
|
||||||
|
|
||||||
#self.dash_shader = SHADERS['dashed_line']
|
# self.dash_shader = SHADERS['dashed_line']
|
||||||
|
|
||||||
|
|
||||||
#self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(self.draw_callback, (), 'WINDOW', 'POST_PIXEL')
|
# self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(self.draw_callback, (), 'WINDOW', 'POST_PIXEL')
|
||||||
context.window_manager.modal_handler_add(self)
|
context.window_manager.modal_handler_add(self)
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
def change_transform_type(self):
|
def change_transform_type(self):
|
||||||
indices = {0: 1, 1:2, 2:1}
|
indices = {0: 1, 1: 2, 2: 1}
|
||||||
index = self.transform_types.index(self.transform_type)
|
index = self.transform_types.index(self.transform_type)
|
||||||
new_index = indices[index]
|
new_index = indices[index]
|
||||||
self.transform_type = self.transform_types[new_index]
|
self.transform_type = self.transform_types[new_index]
|
||||||
@ -237,73 +247,73 @@ class RP_OT_picker_transform(Operator):
|
|||||||
def release_event(self, context):
|
def release_event(self, context):
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
|
|
||||||
# Insert keyframe
|
# Insert keyframe
|
||||||
#bpy.ops.ed.undo_push(message="Transform")
|
# bpy.ops.ed.undo_push(message="Transform")
|
||||||
if scn.tool_settings.use_keyframe_insert_auto:
|
if scn.tool_settings.use_keyframe_insert_auto:
|
||||||
try:
|
try:
|
||||||
bpy.ops.animtoolbox.insert_keyframe()
|
bpy.ops.animtoolbox.insert_keyframe()
|
||||||
except Exception:
|
except Exception:
|
||||||
self.report({"WARNING"}, 'You need animtoolbox addon for inserting keyframe')
|
self.report(
|
||||||
|
{"WARNING"}, "You need animtoolbox addon for inserting keyframe"
|
||||||
|
)
|
||||||
|
|
||||||
self.exit(context)
|
self.exit(context)
|
||||||
|
|
||||||
def exit(self, context):
|
def exit(self, context):
|
||||||
#bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
|
# bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW')
|
||||||
context.window.cursor_modal_restore()
|
context.window.cursor_modal_restore()
|
||||||
#context.region.tag_redraw()
|
# context.region.tag_redraw()
|
||||||
|
|
||||||
def modal(self, context, event):
|
def modal(self, context, event):
|
||||||
scn = context.scene
|
scn = context.scene
|
||||||
self.mouse = Vector((event.mouse_region_x, event.mouse_region_y))
|
self.mouse = Vector((event.mouse_region_x, event.mouse_region_y))
|
||||||
|
|
||||||
if self.mode == 'ROTATE':
|
if self.mode == "ROTATE":
|
||||||
delta = (event.mouse_region_x - self.mouse_start[0]) / 100
|
delta = (event.mouse_region_x - self.mouse_start[0]) / 100
|
||||||
elif self.mode == 'SCALE':
|
elif self.mode == "SCALE":
|
||||||
delta = 1 + (event.mouse_region_x - self.mouse_start[0]) / 100
|
delta = 1 + (event.mouse_region_x - self.mouse_start[0]) / 100
|
||||||
#delta = (self.mouse - self.view_center).length / (self.mouse_start - self.view_center).length
|
# delta = (self.mouse - self.view_center).length / (self.mouse_start - self.view_center).length
|
||||||
|
|
||||||
|
|
||||||
transform_type = self.transform_type
|
transform_type = self.transform_type
|
||||||
#self.batch = batch_for_shader(self.dash_shader, 'LINE_STRIP', {"pos": [self.mouse_start, self.mouse]})
|
# self.batch = batch_for_shader(self.dash_shader, 'LINE_STRIP', {"pos": [self.mouse_start, self.mouse]})
|
||||||
#context.area.tag_redraw()
|
# context.area.tag_redraw()
|
||||||
|
|
||||||
#print(event.type, event.value)
|
# print(event.type, event.value)
|
||||||
if self.mode == 'ROTATE' and event.type == "R" and event.value == 'PRESS':
|
if self.mode == "ROTATE" and event.type == "R" and event.value == "PRESS":
|
||||||
with context.temp_override(**self.override):
|
with context.temp_override(**self.override):
|
||||||
self.exit(context)
|
self.exit(context)
|
||||||
bpy.ops.transform.trackball('INVOKE_DEFAULT')
|
bpy.ops.transform.trackball("INVOKE_DEFAULT")
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
if event.type == "LEFTMOUSE" and event.value == 'RELEASE':
|
if event.type == "LEFTMOUSE" and event.value == "RELEASE":
|
||||||
self.release_event(context)
|
self.release_event(context)
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
if event.type in {"RIGHTMOUSE", "ESC"}:
|
if event.type in {"RIGHTMOUSE", "ESC"}:
|
||||||
for bone, matrix in self.bone_data.items():
|
for bone, matrix in self.bone_data.items():
|
||||||
bone.matrix = matrix
|
bone.matrix = matrix
|
||||||
self.exit(context)
|
self.exit(context)
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
elif event.type == "X" and event.value == 'PRESS':
|
elif event.type == "X" and event.value == "PRESS":
|
||||||
self.change_transform_type()
|
self.change_transform_type()
|
||||||
self.view_vector = Vector((1, 0, 0))
|
self.view_vector = Vector((1, 0, 0))
|
||||||
#transform_type = self.transform_orientation
|
# transform_type = self.transform_orientation
|
||||||
|
|
||||||
elif event.type == "Y" and event.value == 'PRESS':
|
elif event.type == "Y" and event.value == "PRESS":
|
||||||
self.change_transform_type()
|
self.change_transform_type()
|
||||||
self.view_vector = Vector((0, 1, 0))
|
self.view_vector = Vector((0, 1, 0))
|
||||||
#transform_type = self.transform_orientation
|
# transform_type = self.transform_orientation
|
||||||
|
|
||||||
elif event.type == "Z" and event.value == 'PRESS':
|
elif event.type == "Z" and event.value == "PRESS":
|
||||||
self.change_transform_type()
|
self.change_transform_type()
|
||||||
self.view_vector = Vector((0, 0, 1))
|
self.view_vector = Vector((0, 0, 1))
|
||||||
#transform_type = self.transform_orientation
|
# transform_type = self.transform_orientation
|
||||||
|
|
||||||
elif event.type == "MOUSEMOVE":
|
elif event.type == "MOUSEMOVE":
|
||||||
|
if self.mode == "ROTATE":
|
||||||
if self.mode == 'ROTATE':
|
|
||||||
transform_matrix = Matrix.Rotation(delta, 4, self.view_vector)
|
transform_matrix = Matrix.Rotation(delta, 4, self.view_vector)
|
||||||
elif self.mode == 'SCALE':
|
elif self.mode == "SCALE":
|
||||||
if self.view_vector.length:
|
if self.view_vector.length:
|
||||||
transform_matrix = Matrix.Scale(delta, 4, self.view_vector)
|
transform_matrix = Matrix.Scale(delta, 4, self.view_vector)
|
||||||
else:
|
else:
|
||||||
@ -314,14 +324,14 @@ class RP_OT_picker_transform(Operator):
|
|||||||
if scn.tool_settings.transform_pivot_point == "INDIVIDUAL_ORIGINS":
|
if scn.tool_settings.transform_pivot_point == "INDIVIDUAL_ORIGINS":
|
||||||
center = matrix.to_translation()
|
center = matrix.to_translation()
|
||||||
|
|
||||||
if self.mode == 'ROTATE':
|
if self.mode == "ROTATE":
|
||||||
if transform_type == 'LOCAL':
|
if transform_type == "LOCAL":
|
||||||
view_vector = self.view_vector.copy()
|
view_vector = self.view_vector.copy()
|
||||||
view_vector.rotate(matrix)
|
view_vector.rotate(matrix)
|
||||||
transform_matrix = Matrix.Rotation(delta, 4, view_vector)
|
transform_matrix = Matrix.Rotation(delta, 4, view_vector)
|
||||||
|
|
||||||
elif self.mode == 'SCALE':
|
elif self.mode == "SCALE":
|
||||||
if transform_type == 'LOCAL':
|
if transform_type == "LOCAL":
|
||||||
view_vector = self.view_vector.copy()
|
view_vector = self.view_vector.copy()
|
||||||
view_vector.rotate(matrix)
|
view_vector.rotate(matrix)
|
||||||
transform_matrix = Matrix.Scale(delta, 4, view_vector)
|
transform_matrix = Matrix.Scale(delta, 4, view_vector)
|
||||||
@ -335,40 +345,40 @@ class RP_OT_picker_transform(Operator):
|
|||||||
|
|
||||||
bone.matrix = mat
|
bone.matrix = mat
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_toogle_property(Operator):
|
class RP_OT_toogle_property(Operator):
|
||||||
"""Invert a bone custom property"""
|
"""Invert a bone custom property"""
|
||||||
|
|
||||||
bl_idname = "rigpicker.toogle_property"
|
bl_idname = "rigpicker.toogle_property"
|
||||||
bl_label = 'Toogle Property'
|
bl_label = "Toogle Property"
|
||||||
|
|
||||||
data_path : StringProperty()
|
data_path: StringProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return is_picker_space(context.space_data)
|
return is_picker_space(context.space_data)
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = ob.path_resolve(self.data_path)
|
value = ob.path_resolve(self.data_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
data = ob
|
data = ob
|
||||||
prop_name = self.data_path
|
prop_name = self.data_path
|
||||||
#if '.' in self.data_path:
|
# if '.' in self.data_path:
|
||||||
# data, prop = prop_name.rsplit('.', 1)
|
# data, prop = prop_name.rsplit('.', 1)
|
||||||
|
|
||||||
value = type(value)(not value)
|
|
||||||
exec(f'{repr(ob)}.{self.data_path} = {value}')
|
|
||||||
|
|
||||||
#setattr(data, prop_name, value)
|
value = type(value)(not value)
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
exec(f"{repr(ob)}.{self.data_path} = {value}")
|
||||||
bpy.ops.object.mode_set(mode='POSE')
|
|
||||||
|
# setattr(data, prop_name, value)
|
||||||
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
|
bpy.ops.object.mode_set(mode="POSE")
|
||||||
|
|
||||||
if context.scene.tool_settings.use_keyframe_insert_auto:
|
if context.scene.tool_settings.use_keyframe_insert_auto:
|
||||||
bone_name, _ = split_path(self.data_path)
|
bone_name, _ = split_path(self.data_path)
|
||||||
@ -376,42 +386,45 @@ class RP_OT_toogle_property(Operator):
|
|||||||
|
|
||||||
context.area.tag_redraw()
|
context.area.tag_redraw()
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_reload_picker(Operator):
|
class RP_OT_reload_picker(Operator):
|
||||||
"""Reload the picker shapes"""
|
"""Reload the picker shapes"""
|
||||||
|
|
||||||
bl_idname = "rigpicker.reload_picker"
|
bl_idname: str = "rigpicker.reload_picker"
|
||||||
bl_label = 'Reload Picker'
|
bl_label: str = "Reload Picker"
|
||||||
|
|
||||||
#@classmethod
|
# @classmethod
|
||||||
#def poll(cls, context):
|
# def poll(cls, context):
|
||||||
# if not is_picker_space(context):
|
# if not is_picker_space(context):
|
||||||
# return
|
# return
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context: bpy.types.Context):
|
||||||
if context.object.type == 'ARMATURE':
|
if not context.object:
|
||||||
|
return
|
||||||
|
if context.object.type == "ARMATURE":
|
||||||
rig = context.object
|
rig = context.object
|
||||||
else:
|
else:
|
||||||
collection = get_picker_collection(context.object)
|
collection = get_picker_collection(context.object)
|
||||||
rig = collection.rig_picker.rig
|
rig = collection.rig_picker.rig
|
||||||
|
|
||||||
#print('Reload', rig)
|
# print('Reload', rig)
|
||||||
load_picker_data(rig)
|
load_picker_data(rig)
|
||||||
|
|
||||||
for area in context.screen.areas:
|
if context.screen:
|
||||||
if is_picker_space(area.spaces.active):
|
for area in context.screen.areas:
|
||||||
area.tag_redraw()
|
if is_picker_space(area.spaces.active):
|
||||||
|
area.tag_redraw()
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_toogle_bone_layer(Operator):
|
class RP_OT_toogle_bone_layer(Operator):
|
||||||
"""Toogle bone layer visibility when double clicking on a bone"""
|
"""Toogle bone layer visibility when double clicking on a bone"""
|
||||||
bl_idname = "rigpicker.toogle_bone_layer"
|
|
||||||
bl_label = 'Toogle Bone Layer'
|
bl_idname: str = "rigpicker.toogle_bone_layer"
|
||||||
|
bl_label: str = "Toogle Bone Layer"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -421,7 +434,7 @@ class RP_OT_toogle_bone_layer(Operator):
|
|||||||
ob = context.object
|
ob = context.object
|
||||||
picker = PICKERS.get(ob)
|
picker = PICKERS.get(ob)
|
||||||
|
|
||||||
if picker.hover_shape and picker.hover_shape.type == 'bone':
|
if picker.hover_shape and picker.hover_shape.type == "bone":
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
@ -442,62 +455,64 @@ class RP_OT_toogle_bone_layer(Operator):
|
|||||||
|
|
||||||
class RP_OT_context_menu_picker(Operator):
|
class RP_OT_context_menu_picker(Operator):
|
||||||
"""Display Menu with the custom properties of the hovered bone if any or the active bone"""
|
"""Display Menu with the custom properties of the hovered bone if any or the active bone"""
|
||||||
|
|
||||||
bl_idname = "node.context_menu_picker"
|
bl_idname = "node.context_menu_picker"
|
||||||
bl_label = 'Context Menu Picker'
|
bl_label = "Context Menu Picker"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return is_picker_space(context.space_data)
|
return is_picker_space(context.space_data)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
bpy.ops.wm.call_menu(name='RP_MT_context_menu')
|
bpy.ops.wm.call_menu(name="RP_MT_context_menu")
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_pack_picker(Operator):
|
class RP_OT_pack_picker(Operator):
|
||||||
"""Pack Unpack the picker on the rig"""
|
"""Pack Unpack the picker on the rig"""
|
||||||
|
|
||||||
bl_idname = "rigpicker.pack_picker"
|
bl_idname = "rigpicker.pack_picker"
|
||||||
bl_label = 'Pack Picker'
|
bl_label = "Pack Picker"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
return (ob and ob.type == 'ARMATURE' and ob.data.rig_picker.sources)
|
return ob and ob.type == "ARMATURE" and ob.data.rig_picker.sources
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
print('Pack Pickers...')
|
print("Pack Pickers...")
|
||||||
|
|
||||||
rig = context.object
|
rig = context.object
|
||||||
|
|
||||||
if 'pickers' in rig.data.rig_picker.keys():
|
if "pickers" in rig.data.rig_picker.keys():
|
||||||
unpack_picker(rig)
|
unpack_picker(rig)
|
||||||
self.report({"INFO"}, f'The picker is unpacked')
|
self.report({"INFO"}, f"The picker is unpacked")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
pack_picker(rig)
|
pack_picker(rig)
|
||||||
|
|
||||||
if not rig.data.rig_picker['pickers']:
|
if not rig.data.rig_picker["pickers"]:
|
||||||
self.report({"ERROR"}, f'No picker have been packed')
|
self.report({"ERROR"}, f"No picker have been packed")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
elif len(rig.data.rig_picker['pickers']) < len(rig.data.rig_picker.sources):
|
elif len(rig.data.rig_picker["pickers"]) < len(rig.data.rig_picker.sources):
|
||||||
self.report({"WARNING"}, f'No all pickers have been packed')
|
self.report({"WARNING"}, f"No all pickers have been packed")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
self.report({"INFO"}, f'The picker is packed')
|
self.report({"INFO"}, f"The picker is packed")
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_call_operator(Operator):
|
class RP_OT_call_operator(Operator):
|
||||||
bl_idname = "rigpicker.call_operator"
|
bl_idname = "rigpicker.call_operator"
|
||||||
bl_label = 'Call operator'
|
bl_label = "Call operator"
|
||||||
|
|
||||||
operator : StringProperty()
|
operator: StringProperty()
|
||||||
arguments : StringProperty()
|
arguments: StringProperty()
|
||||||
invoke: BoolProperty()
|
invoke: BoolProperty()
|
||||||
view_3d : BoolProperty()
|
view_3d: BoolProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -509,30 +524,30 @@ class RP_OT_call_operator(Operator):
|
|||||||
op = eval_attr(bpy.ops, properties.operator).get_rna_type()
|
op = eval_attr(bpy.ops, properties.operator).get_rna_type()
|
||||||
return op.description
|
return op.description
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return 'Call operator'
|
return "Call operator"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
#context.area.tag_redraw()
|
# context.area.tag_redraw()
|
||||||
|
|
||||||
override = {}
|
override = {}
|
||||||
if self.view_3d:
|
if self.view_3d:
|
||||||
override = get_view_3d_override()
|
override = get_view_3d_override()
|
||||||
|
|
||||||
arguments = json.loads(self.arguments or "{}")
|
arguments = json.loads(self.arguments or "{}")
|
||||||
|
|
||||||
with context.temp_override(**override):
|
with context.temp_override(**override):
|
||||||
try:
|
try:
|
||||||
ops = eval_attr(bpy.ops, self.operator)
|
ops = eval_attr(bpy.ops, self.operator)
|
||||||
if self.invoke:
|
if self.invoke:
|
||||||
ops('INVOKE_DEFAULT', **arguments)
|
ops("INVOKE_DEFAULT", **arguments)
|
||||||
else:
|
else:
|
||||||
ops(**arguments)
|
ops(**arguments)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
self.report({"ERROR"}, f'The operator {self.operator} cannot be called')
|
self.report({"ERROR"}, f"The operator {self.operator} cannot be called")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
context.area.tag_redraw()
|
context.area.tag_redraw()
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@ -545,72 +560,77 @@ class RP_MT_context_menu(Menu):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
col = layout.column()
|
col = layout.column()
|
||||||
col.operator_context = 'INVOKE_DEFAULT'
|
col.operator_context = "INVOKE_DEFAULT"
|
||||||
#col.use_property_split = True
|
# col.use_property_split = True
|
||||||
|
|
||||||
ob = context.object
|
ob = context.object
|
||||||
picker = PICKERS.get(ob)
|
picker = PICKERS.get(ob)
|
||||||
|
|
||||||
if picker.hover_shape and picker.hover_shape.type == 'bone':
|
if picker.hover_shape and picker.hover_shape.type == "bone":
|
||||||
bone = picker.hover_shape.bone
|
bone = picker.hover_shape.bone
|
||||||
else:
|
else:
|
||||||
bone = context.active_pose_bone
|
bone = context.active_pose_bone
|
||||||
|
|
||||||
# Draw Space Switch Operator
|
# Draw Space Switch Operator
|
||||||
if getattr(ob.data, 'space_switch'):
|
if getattr(ob.data, "space_switch"):
|
||||||
space_switch = ob.data.space_switch
|
space_switch = ob.data.space_switch
|
||||||
|
|
||||||
data_paths = [f'pose.bones["{bone.name}"]["{k}"]' for k in bone.keys()]
|
data_paths = [f'pose.bones["{bone.name}"]["{k}"]' for k in bone.keys()]
|
||||||
space_bone = next((s for s in space_switch.bones if s.data_path in data_paths), None)
|
space_bone = next(
|
||||||
|
(s for s in space_switch.bones if s.data_path in data_paths), None
|
||||||
|
)
|
||||||
if space_bone:
|
if space_bone:
|
||||||
|
|
||||||
index = list(space_switch.bones).index(space_bone)
|
index = list(space_switch.bones).index(space_bone)
|
||||||
value = ob.path_resolve(space_bone.data_path)
|
value = ob.path_resolve(space_bone.data_path)
|
||||||
space = next((s.name for s in space_bone.spaces if s.value == value), None)
|
space = next(
|
||||||
|
(s.name for s in space_bone.spaces if s.value == value), None
|
||||||
|
)
|
||||||
|
|
||||||
op = col.operator("spaceswitch.change_space", text=f'({space})', icon='PINNED')
|
op = col.operator(
|
||||||
op.index=index
|
"spaceswitch.change_space", text=f"({space})", icon="PINNED"
|
||||||
|
)
|
||||||
|
op.index = index
|
||||||
col.separator()
|
col.separator()
|
||||||
|
|
||||||
if bone:
|
if bone:
|
||||||
for key in bone.keys():
|
for key in bone.keys():
|
||||||
col.prop(bone,f'["{key}"]', slider=True)
|
col.prop(bone, f'["{key}"]', slider=True)
|
||||||
|
|
||||||
#layout.operator("rigpicker.show_bone_layer", text="Show Bone Layer", ).type = 'ACTIVE'
|
# layout.operator("rigpicker.show_bone_layer", text="Show Bone Layer", ).type = 'ACTIVE'
|
||||||
#layout.operator("rigidbody.objects_add", text="B Add Passive").type = 'PASSIVE'
|
# layout.operator("rigidbody.objects_add", text="B Add Passive").type = 'PASSIVE'
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_add_picker_collection(Operator):
|
class RP_OT_add_picker_collection(Operator):
|
||||||
bl_idname = "rigpicker.add_picker_collection"
|
bl_idname = "rigpicker.add_picker_collection"
|
||||||
bl_label = "Add a Picker Collection"
|
bl_label = "Add a Picker Collection"
|
||||||
bl_description = "Add a Picker Collection"
|
bl_description = "Add a Picker Collection"
|
||||||
bl_options = {'UNDO', 'REGISTER'}
|
bl_options = {"UNDO", "REGISTER"}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
return (ob and ob.type == 'ARMATURE')
|
return ob and ob.type == "ARMATURE"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
scn = context.scene
|
scn = context.scene
|
||||||
ob = context.object
|
ob = context.object
|
||||||
|
|
||||||
name = ob.name
|
name = ob.name
|
||||||
if name.endswith('_rig'):
|
if name.endswith("_rig"):
|
||||||
name = name[:-4]
|
name = name[:-4]
|
||||||
|
|
||||||
canvas_name = f'canevas_{name}'
|
canvas_name = f"canevas_{name}"
|
||||||
canvas_points = [(-0.5, 0.5, 0), (0.5, 0.5, 0), (0.5, -0.5, 0), (-0.5, -0.5, 0)]
|
canvas_points = [(-0.5, 0.5, 0), (0.5, 0.5, 0), (0.5, -0.5, 0), (-0.5, -0.5, 0)]
|
||||||
canvas_faces = [(0, 1, 2, 3)]
|
canvas_faces = [(0, 1, 2, 3)]
|
||||||
|
|
||||||
canvas_mesh = bpy.data.meshes.new(canvas_name)
|
canvas_mesh = bpy.data.meshes.new(canvas_name)
|
||||||
canvas_mesh.from_pydata(canvas_points, [], canvas_faces)
|
canvas_mesh.from_pydata(canvas_points, [], canvas_faces)
|
||||||
canvas_mesh.update(calc_edges=True)
|
canvas_mesh.update(calc_edges=True)
|
||||||
|
|
||||||
canvas_ob = bpy.data.objects.new(canvas_name, canvas_mesh)
|
canvas_ob = bpy.data.objects.new(canvas_name, canvas_mesh)
|
||||||
canvas_ob.rig_picker.shape_type = 'DISPLAY'
|
canvas_ob.rig_picker.shape_type = "DISPLAY"
|
||||||
|
|
||||||
col = bpy.data.collections.new(f'Picker {name}')
|
col = bpy.data.collections.new(f"Picker {name}")
|
||||||
col.rig_picker.enabled = True
|
col.rig_picker.enabled = True
|
||||||
col.rig_picker.rig = ob
|
col.rig_picker.rig = ob
|
||||||
col.rig_picker.canvas = canvas_ob
|
col.rig_picker.canvas = canvas_ob
|
||||||
@ -621,44 +641,44 @@ class RP_OT_add_picker_collection(Operator):
|
|||||||
|
|
||||||
self.report({"INFO"}, f"New Picker Collection {col.name} Created")
|
self.report({"INFO"}, f"New Picker Collection {col.name} Created")
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_add_picker_source(Operator):
|
class RP_OT_add_picker_source(Operator):
|
||||||
bl_idname = "rigpicker.add_picker_source"
|
bl_idname = "rigpicker.add_picker_source"
|
||||||
bl_label = "Add a Picker source"
|
bl_label = "Add a Picker source"
|
||||||
bl_description = "Add a Picker source"
|
bl_description = "Add a Picker source"
|
||||||
bl_options = {'UNDO', 'REGISTER'}
|
bl_options = {"UNDO", "REGISTER"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
arm = context.object.data
|
arm = context.object.data
|
||||||
arm.rig_picker.sources.add()
|
arm.rig_picker.sources.add()
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_remove_picker_source(Operator):
|
class RP_OT_remove_picker_source(Operator):
|
||||||
bl_idname = "rigpicker.remove_picker_source"
|
bl_idname = "rigpicker.remove_picker_source"
|
||||||
bl_label = "Delete a Picker source"
|
bl_label = "Delete a Picker source"
|
||||||
bl_description = "Delete a Picker source"
|
bl_description = "Delete a Picker source"
|
||||||
bl_options = {'UNDO', 'REGISTER'}
|
bl_options = {"UNDO", "REGISTER"}
|
||||||
|
|
||||||
index : IntProperty(default=-1)
|
index: IntProperty(default=-1)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
arm = context.object.data
|
arm = context.object.data
|
||||||
arm.rig_picker.sources.remove(self.index)
|
arm.rig_picker.sources.remove(self.index)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_fit_picker(Operator):
|
class RP_OT_fit_picker(Operator):
|
||||||
bl_idname = "rigpicker.fit_picker"
|
bl_idname = "rigpicker.fit_picker"
|
||||||
bl_label = "Fit Picker"
|
bl_label = "Fit Picker"
|
||||||
bl_description = "Fit Picker in 2d view"
|
bl_description = "Fit Picker in 2d view"
|
||||||
bl_options = {'UNDO', 'REGISTER'}
|
bl_options = {"UNDO", "REGISTER"}
|
||||||
|
|
||||||
index : IntProperty()
|
index: IntProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -675,17 +695,22 @@ class RP_OT_fit_picker(Operator):
|
|||||||
view2d = context.region.view2d
|
view2d = context.region.view2d
|
||||||
|
|
||||||
if self.index == -1:
|
if self.index == -1:
|
||||||
#print('Picker Group')
|
# print('Picker Group')
|
||||||
picker = picker_group
|
picker = picker_group
|
||||||
|
|
||||||
view_rect = [view2d.view_to_region(*co, clip=False) for co in picker.rect]
|
view_rect = [view2d.view_to_region(*co, clip=False) for co in picker.rect]
|
||||||
bpy.ops.view2d.zoom_border(
|
bpy.ops.view2d.zoom_border(
|
||||||
xmin=round(view_rect[3][0]), xmax=round(view_rect[1][0]),
|
xmin=round(view_rect[3][0]),
|
||||||
ymin=round(view_rect[3][1]), ymax=round(view_rect[1][1]),
|
xmax=round(view_rect[1][0]),
|
||||||
wait_for_input=False, zoom_out=False
|
ymin=round(view_rect[3][1]),
|
||||||
|
ymax=round(view_rect[1][1]),
|
||||||
|
wait_for_input=False,
|
||||||
|
zoom_out=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
region_center = Vector((context.region.width * 0.5, context.region.height * 0.5))
|
region_center = Vector(
|
||||||
|
(context.region.width * 0.5, context.region.height * 0.5)
|
||||||
|
)
|
||||||
view_center = view2d.region_to_view(*region_center)
|
view_center = view2d.region_to_view(*region_center)
|
||||||
|
|
||||||
view_offset = Vector(view_center) + (picker.center - Vector(view_center))
|
view_offset = Vector(view_center) + (picker.center - Vector(view_center))
|
||||||
@ -695,21 +720,27 @@ class RP_OT_fit_picker(Operator):
|
|||||||
|
|
||||||
bpy.ops.view2d.pan(deltax=round(delta[0]), deltay=round(delta[1]))
|
bpy.ops.view2d.pan(deltax=round(delta[0]), deltay=round(delta[1]))
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
keymaps = []
|
keymaps = []
|
||||||
|
|
||||||
|
|
||||||
def register_keymaps():
|
def register_keymaps():
|
||||||
wm = bpy.context.window_manager
|
wm = bpy.context.window_manager
|
||||||
|
|
||||||
km = wm.keyconfigs.addon.keymaps.new(name="Node Editor", space_type="NODE_EDITOR")
|
km = wm.keyconfigs.addon.keymaps.new(name="Node Editor", space_type="NODE_EDITOR")
|
||||||
|
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
kmi = km.keymap_items.new("rigpicker.fit_picker", type=f"NUMPAD_{i}", value="PRESS")
|
kmi = km.keymap_items.new(
|
||||||
|
"rigpicker.fit_picker", type=f"NUMPAD_{i}", value="PRESS"
|
||||||
|
)
|
||||||
kmi.properties.index = i - 1
|
kmi.properties.index = i - 1
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="NUMPAD_PERIOD", value="PRESS")
|
kmi = km.keymap_items.new(
|
||||||
|
"rigpicker.call_operator", type="NUMPAD_PERIOD", value="PRESS"
|
||||||
|
)
|
||||||
kmi.properties.operator = "view3d.view_selected"
|
kmi.properties.operator = "view3d.view_selected"
|
||||||
kmi.properties.view_3d = True
|
kmi.properties.view_3d = True
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
@ -719,12 +750,16 @@ def register_keymaps():
|
|||||||
kmi.properties.arguments = '{"action": "SELECT"}'
|
kmi.properties.arguments = '{"action": "SELECT"}'
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="A", value="PRESS", alt=True)
|
kmi = km.keymap_items.new(
|
||||||
|
"rigpicker.call_operator", type="A", value="PRESS", alt=True
|
||||||
|
)
|
||||||
kmi.properties.operator = "pose.select_all"
|
kmi.properties.operator = "pose.select_all"
|
||||||
kmi.properties.arguments = '{"action": "DESELECT"}'
|
kmi.properties.arguments = '{"action": "DESELECT"}'
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.toogle_bone_layer", type="LEFTMOUSE", value="DOUBLE_CLICK")
|
kmi = km.keymap_items.new(
|
||||||
|
"rigpicker.toogle_bone_layer", type="LEFTMOUSE", value="DOUBLE_CLICK"
|
||||||
|
)
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="X", value="PRESS")
|
kmi = km.keymap_items.new("rigpicker.call_operator", type="X", value="PRESS")
|
||||||
@ -735,55 +770,69 @@ def register_keymaps():
|
|||||||
kmi.properties.operator = "animtoolbox.insert_keyframe"
|
kmi.properties.operator = "animtoolbox.insert_keyframe"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("anim.keyframe_delete_v3d", type="K", value="PRESS", alt=True)
|
kmi = km.keymap_items.new(
|
||||||
|
"anim.keyframe_delete_v3d", type="K", value="PRESS", alt=True
|
||||||
|
)
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="G", value="PRESS")
|
kmi = km.keymap_items.new("rigpicker.call_operator", type="G", value="PRESS")
|
||||||
kmi.properties.operator = 'transform.translate'
|
kmi.properties.operator = "transform.translate"
|
||||||
kmi.properties.view_3d = True
|
kmi.properties.view_3d = True
|
||||||
kmi.properties.invoke = True
|
kmi.properties.invoke = True
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="G", value="PRESS", alt=True)
|
kmi = km.keymap_items.new(
|
||||||
kmi.properties.operator = 'pose.loc_clear'
|
"rigpicker.call_operator", type="G", value="PRESS", alt=True
|
||||||
|
)
|
||||||
|
kmi.properties.operator = "pose.loc_clear"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("node.picker_transform", type="R", value="PRESS")
|
kmi = km.keymap_items.new("node.picker_transform", type="R", value="PRESS")
|
||||||
kmi.properties.mode = 'ROTATE'
|
kmi.properties.mode = "ROTATE"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="R", value="PRESS", alt=True)
|
kmi = km.keymap_items.new(
|
||||||
kmi.properties.operator = 'pose.rot_clear'
|
"rigpicker.call_operator", type="R", value="PRESS", alt=True
|
||||||
|
)
|
||||||
|
kmi.properties.operator = "pose.rot_clear"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("node.picker_transform", type="S", value="PRESS")
|
kmi = km.keymap_items.new("node.picker_transform", type="S", value="PRESS")
|
||||||
kmi.properties.mode = 'SCALE'
|
kmi.properties.mode = "SCALE"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("rigpicker.call_operator", type="S", value="PRESS", alt=True)
|
kmi = km.keymap_items.new(
|
||||||
kmi.properties.operator = 'pose.scale_clear'
|
"rigpicker.call_operator", type="S", value="PRESS", alt=True
|
||||||
|
)
|
||||||
|
kmi.properties.operator = "pose.scale_clear"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("node.context_menu_picker", type="RIGHTMOUSE", value="PRESS")
|
kmi = km.keymap_items.new(
|
||||||
|
"node.context_menu_picker", type="RIGHTMOUSE", value="PRESS"
|
||||||
|
)
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("node.rp_box_select", type="LEFTMOUSE", value="PRESS")
|
kmi = km.keymap_items.new("node.rp_box_select", type="LEFTMOUSE", value="PRESS")
|
||||||
kmi.properties.mode = 'SET'
|
kmi.properties.mode = "SET"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
kmi = km.keymap_items.new("node.rp_box_select", type="LEFTMOUSE", value="PRESS", shift=True)
|
kmi = km.keymap_items.new(
|
||||||
kmi.properties.mode = 'EXTEND'
|
"node.rp_box_select", type="LEFTMOUSE", value="PRESS", shift=True
|
||||||
|
)
|
||||||
|
kmi.properties.mode = "EXTEND"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
#kmi = km.keymap_items.new("node.rp_box_select", type="LEFTMOUSE", value="PRESS", ctrl=True)
|
# kmi = km.keymap_items.new("node.rp_box_select", type="LEFTMOUSE", value="PRESS", ctrl=True)
|
||||||
kmi = km.keymap_items.new("node.rp_box_select", type="LEFTMOUSE", value="PRESS", alt=True)
|
kmi = km.keymap_items.new(
|
||||||
kmi.properties.mode = 'SUBSTRACT'
|
"node.rp_box_select", type="LEFTMOUSE", value="PRESS", alt=True
|
||||||
|
)
|
||||||
|
kmi.properties.mode = "SUBSTRACT"
|
||||||
keymaps.append((km, kmi))
|
keymaps.append((km, kmi))
|
||||||
|
|
||||||
#km = wm.keyconfigs.addon.keymaps.new(name="View2D")
|
# km = wm.keyconfigs.addon.keymaps.new(name="View2D")
|
||||||
#kmi = km.keymap_items.new("rigpicker.call_operator", type="MIDDLEMOUSE", value="PRESS")
|
# kmi = km.keymap_items.new("rigpicker.call_operator", type="MIDDLEMOUSE", value="PRESS")
|
||||||
#kmi.properties.operator = "bpy.ops.view2d.pan('INVOKE_DEFAULT')"
|
# kmi.properties.operator = "bpy.ops.view2d.pan('INVOKE_DEFAULT')"
|
||||||
#keymaps.append((km, kmi))
|
# keymaps.append((km, kmi))
|
||||||
|
|
||||||
|
|
||||||
def unregister_keymaps():
|
def unregister_keymaps():
|
||||||
@ -791,6 +840,7 @@ def unregister_keymaps():
|
|||||||
km.keymap_items.remove(kmi)
|
km.keymap_items.remove(kmi)
|
||||||
keymaps.clear()
|
keymaps.clear()
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
RP_OT_box_select,
|
RP_OT_box_select,
|
||||||
RP_OT_toogle_property,
|
RP_OT_toogle_property,
|
||||||
@ -804,19 +854,19 @@ classes = (
|
|||||||
RP_OT_add_picker_source,
|
RP_OT_add_picker_source,
|
||||||
RP_OT_remove_picker_source,
|
RP_OT_remove_picker_source,
|
||||||
RP_OT_fit_picker,
|
RP_OT_fit_picker,
|
||||||
RP_OT_add_picker_collection
|
RP_OT_add_picker_collection,
|
||||||
#RP_OT_ui_draw
|
# RP_OT_ui_draw
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
register_keymaps()
|
register_keymaps()
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
unregister_keymaps()
|
unregister_keymaps()
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
from os.path import abspath
|
from os.path import abspath
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -13,23 +12,23 @@ from ..core.bl_utils import link_mat_to_object, flip_name
|
|||||||
|
|
||||||
|
|
||||||
class RP_OT_create_shape(Operator):
|
class RP_OT_create_shape(Operator):
|
||||||
bl_label = 'Create UI shape'
|
bl_label = "Create UI shape"
|
||||||
bl_idname = 'rigpicker.create_shape'
|
bl_idname = "rigpicker.create_shape"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return (context.object and context.object.mode == 'POSE')
|
return context.object and context.object.mode == "POSE"
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
return context.window_manager.invoke_props_dialog(self)
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
for col in bpy.data.collections:
|
for col in bpy.data.collections:
|
||||||
if col.rig_picker.enabled:
|
if col.rig_picker.enabled:
|
||||||
self.layout.prop(col.rig_picker, 'link_shape', text=col.name)
|
self.layout.prop(col.rig_picker, "link_shape", text=col.name)
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
scn = context.scene
|
scn = context.scene
|
||||||
vl = context.view_layer
|
vl = context.view_layer
|
||||||
|
|
||||||
@ -42,13 +41,15 @@ class RP_OT_create_shape(Operator):
|
|||||||
|
|
||||||
ob.rig_picker.name = name
|
ob.rig_picker.name = name
|
||||||
|
|
||||||
verts=[(0,0,0)]
|
verts = [(0, 0, 0)]
|
||||||
edges = []
|
edges = []
|
||||||
faces =[]
|
faces = []
|
||||||
|
|
||||||
mesh.from_pydata(verts, edges, faces)
|
mesh.from_pydata(verts, edges, faces)
|
||||||
|
|
||||||
picker_selected_cols = [col for col in bpy.data.collections if col.rig_picker.link_shape]
|
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]:
|
for col in picker_selected_cols or [scn.collection]:
|
||||||
col.objects.link(ob)
|
col.objects.link(ob)
|
||||||
@ -64,36 +65,36 @@ class RP_OT_create_shape(Operator):
|
|||||||
|
|
||||||
offset += 0.05
|
offset += 0.05
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_name_from_bone(Operator):
|
class RP_OT_name_from_bone(Operator):
|
||||||
bl_label = 'Name Shape from selected bones'
|
bl_label = "Name Shape from selected bones"
|
||||||
bl_idname = 'rigpicker.name_from_bone'
|
bl_idname = "rigpicker.name_from_bone"
|
||||||
bl_description = 'Rename all shapes from related bones name'
|
bl_description = "Rename all shapes from related bones name"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
|
|
||||||
col = get_picker_collection(context.object)
|
col = get_picker_collection(context.object)
|
||||||
|
|
||||||
for ob in col.all_objects:
|
for ob in col.all_objects:
|
||||||
if ob.rig_picker.shape_type == 'BONE':
|
if ob.rig_picker.shape_type == "BONE":
|
||||||
ob.name = ob.rig_picker.name
|
ob.name = ob.rig_picker.name
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_mirror_shape(Operator):
|
class RP_OT_mirror_shape(Operator):
|
||||||
bl_label = 'Mirror UI shape'
|
bl_label = "Mirror UI shape"
|
||||||
bl_idname = 'rigpicker.mirror_shape'
|
bl_idname = "rigpicker.mirror_shape"
|
||||||
#bl_options = g
|
# bl_options = g
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return (context.object and context.object.type in ('MESH', 'CURVE', 'TEXT'))
|
return context.object and context.object.type in ("MESH", "CURVE", "TEXT")
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
collection = get_picker_collection(context.object)
|
collection = get_picker_collection(context.object)
|
||||||
objects = context.selected_objects
|
objects = context.selected_objects
|
||||||
|
|
||||||
@ -103,9 +104,13 @@ class RP_OT_mirror_shape(Operator):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for mod in ob.modifiers:
|
for mod in ob.modifiers:
|
||||||
if (mod.type == 'NODES' and mod.node_group and mod.node_group.name == 'Symmetrize' and
|
if (
|
||||||
mod.get('Socket_2') in objects):
|
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)
|
bpy.data.objects.remove(ob)
|
||||||
|
|
||||||
if collection.rig_picker.symmetry:
|
if collection.rig_picker.symmetry:
|
||||||
@ -116,14 +121,14 @@ class RP_OT_mirror_shape(Operator):
|
|||||||
for ob in objects:
|
for ob in objects:
|
||||||
flipped_name = flip_name(ob.name)
|
flipped_name = flip_name(ob.name)
|
||||||
if flipped_name == ob.name:
|
if flipped_name == ob.name:
|
||||||
suffix = '.L'
|
suffix = ".L"
|
||||||
flipped_suffix = '.R'
|
flipped_suffix = ".R"
|
||||||
# Determine side of the object
|
# Determine side of the object
|
||||||
if ob.matrix_world.to_translation()[0] < x_axis:
|
if ob.matrix_world.to_translation()[0] < x_axis:
|
||||||
suffix, flipped_suffix = flipped_suffix, suffix
|
suffix, flipped_suffix = flipped_suffix, suffix
|
||||||
|
|
||||||
flipped_name = f'{ob.name}{flipped_suffix}'
|
flipped_name = f"{ob.name}{flipped_suffix}"
|
||||||
ob.name = f'{ob.name}{suffix}'
|
ob.name = f"{ob.name}{suffix}"
|
||||||
|
|
||||||
flipped_object = ob.copy()
|
flipped_object = ob.copy()
|
||||||
flipped_object.name = flipped_name
|
flipped_object.name = flipped_name
|
||||||
@ -133,20 +138,20 @@ class RP_OT_mirror_shape(Operator):
|
|||||||
flipped_object.modifiers.remove(mod)
|
flipped_object.modifiers.remove(mod)
|
||||||
|
|
||||||
# Add symmetrize modifier TODO add it into a resource
|
# Add symmetrize modifier TODO add it into a resource
|
||||||
mod = flipped_object.modifiers.new(name='Symmetrize', type='NODES')
|
mod = flipped_object.modifiers.new(name="Symmetrize", type="NODES")
|
||||||
mod.node_group = bpy.data.node_groups['Symmetrize']
|
mod.node_group = bpy.data.node_groups["Symmetrize"]
|
||||||
mod['Socket_2'] = ob
|
mod["Socket_2"] = ob
|
||||||
mod['Socket_3'] = collection.rig_picker.symmetry
|
mod["Socket_3"] = collection.rig_picker.symmetry
|
||||||
|
|
||||||
for col in ob.users_collection:
|
for col in ob.users_collection:
|
||||||
col.objects.link(flipped_object)
|
col.objects.link(flipped_object)
|
||||||
|
|
||||||
if ob.rig_picker.shape_type == 'BONE':
|
if ob.rig_picker.shape_type == "BONE":
|
||||||
flipped_object.rig_picker.name = flip_name(ob.rig_picker.name)
|
flipped_object.rig_picker.name = flip_name(ob.rig_picker.name)
|
||||||
|
|
||||||
elif ob.rig_picker.shape_type == 'FUNCTION':
|
elif ob.rig_picker.shape_type == "FUNCTION":
|
||||||
args = {}
|
args = {}
|
||||||
for key,value in eval(ob.rig_picker.arguments).items():
|
for key, value in eval(ob.rig_picker.arguments).items():
|
||||||
if type(value) == list:
|
if type(value) == list:
|
||||||
mirrored_value = []
|
mirrored_value = []
|
||||||
for item in value:
|
for item in value:
|
||||||
@ -158,32 +163,37 @@ class RP_OT_mirror_shape(Operator):
|
|||||||
|
|
||||||
flipped_object.rig_picker.arguments = str(args)
|
flipped_object.rig_picker.arguments = str(args)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_select_shape_type(Operator):
|
class RP_OT_select_shape_type(Operator):
|
||||||
bl_label = 'Select Shape by Type'
|
bl_label = "Select Shape by Type"
|
||||||
bl_idname = 'rigpicker.select_shape_type'
|
bl_idname = "rigpicker.select_shape_type"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
shape_type = bpy.props.EnumProperty(items =[(i.upper(), i, '') for i in ('Bone', 'Display', 'Function')])
|
shape_type = bpy.props.EnumProperty(
|
||||||
|
items=[(i.upper(), i, "") for i in ("Bone", "Display", "Function")]
|
||||||
|
)
|
||||||
|
|
||||||
def draw(self,context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
col = layout.column()
|
col = layout.column()
|
||||||
col.prop(self,'shape_type', expand=True)
|
col.prop(self, "shape_type", expand=True)
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
#print(self.shape_type)
|
# print(self.shape_type)
|
||||||
canvas = context.scene.rig_picker.canvas
|
canvas = context.scene.rig_picker.canvas
|
||||||
if canvas:
|
if canvas:
|
||||||
for ob in [o for o in bpy.data.objects if o.layers==canvas.layers]:
|
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:
|
if (
|
||||||
|
ob.type in ["MESH", "CURVE", "FONT"]
|
||||||
|
and ob.rig_picker.shape_type == self.shape_type
|
||||||
|
):
|
||||||
ob.select = True
|
ob.select = True
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@ -191,10 +201,10 @@ class RP_OT_select_shape_type(Operator):
|
|||||||
|
|
||||||
|
|
||||||
class RP_OT_save_picker(Operator):
|
class RP_OT_save_picker(Operator):
|
||||||
bl_label = 'Store UI Data'
|
bl_label = "Store UI Data"
|
||||||
bl_idname = 'rigpicker.save_picker'
|
bl_idname = "rigpicker.save_picker"
|
||||||
|
|
||||||
index : IntProperty(default=-1)
|
index: IntProperty(default=-1)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
scn = context.scene
|
scn = context.scene
|
||||||
@ -205,39 +215,51 @@ class RP_OT_save_picker(Operator):
|
|||||||
else:
|
else:
|
||||||
source = context.active_object.data.rig_picker.sources[self.index].source
|
source = context.active_object.data.rig_picker.sources[self.index].source
|
||||||
source = Path(bpy.path.abspath(source, library=ob.data.library)).resolve()
|
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
|
collection = next(
|
||||||
and Path(bpy.path.abspath(c.rig_picker.destination)).resolve() == source), None)
|
(
|
||||||
|
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:
|
if not collection:
|
||||||
self.report({"ERROR"}, 'No Picker found')
|
self.report({"ERROR"}, "No Picker found")
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
canvas = collection.rig_picker.canvas
|
canvas = collection.rig_picker.canvas
|
||||||
#rig = collection.rig_picker.rig
|
# rig = collection.rig_picker.rig
|
||||||
shapes = [o for o in collection.all_objects if o != canvas and o.type in ('MESH', 'CURVE', 'FONT')]
|
shapes = [
|
||||||
|
o
|
||||||
|
for o in collection.all_objects
|
||||||
|
if o != canvas and o.type in ("MESH", "CURVE", "FONT")
|
||||||
|
]
|
||||||
|
|
||||||
if not canvas:
|
if not canvas:
|
||||||
self.report({'ERROR'}, 'Choose a Canvas')
|
self.report({"ERROR"}, "Choose a Canvas")
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
|
||||||
picker_data = get_picker_data(collection)
|
picker_data = get_picker_data(collection)
|
||||||
|
|
||||||
picker_path = Path(bpy.path.abspath(collection.rig_picker.destination))
|
picker_path = Path(bpy.path.abspath(collection.rig_picker.destination))
|
||||||
|
|
||||||
print(f'Save Picker to {picker_path}')
|
print(f"Save Picker to {picker_path}")
|
||||||
picker_path.write_text(json.dumps(picker_data))
|
picker_path.write_text(json.dumps(picker_data))
|
||||||
|
|
||||||
bpy.ops.rigpicker.reload_picker()
|
bpy.ops.rigpicker.reload_picker()
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
RP_OT_create_shape,
|
RP_OT_create_shape,
|
||||||
RP_OT_name_from_bone,
|
RP_OT_name_from_bone,
|
||||||
RP_OT_mirror_shape,
|
RP_OT_mirror_shape,
|
||||||
RP_OT_select_shape_type,
|
RP_OT_select_shape_type,
|
||||||
RP_OT_save_picker
|
RP_OT_save_picker,
|
||||||
)
|
)
|
||||||
|
|
||||||
register, unregister = bpy.utils.register_classes_factory(classes)
|
register, unregister = bpy.utils.register_classes_factory(classes)
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.props import (EnumProperty, StringProperty, PointerProperty, BoolProperty,
|
from bpy.props import (
|
||||||
CollectionProperty, IntProperty)
|
EnumProperty,
|
||||||
|
StringProperty,
|
||||||
|
PointerProperty,
|
||||||
|
BoolProperty,
|
||||||
|
CollectionProperty,
|
||||||
|
IntProperty,
|
||||||
|
)
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
'''
|
"""
|
||||||
def get_operator_items(self,context):
|
def get_operator_items(self,context):
|
||||||
items = []
|
items = []
|
||||||
from . import func_picker as mod
|
from . import func_picker as mod
|
||||||
@ -14,55 +20,58 @@ def get_operator_items(self,context):
|
|||||||
items.append((name,name,""))
|
items.append((name,name,""))
|
||||||
|
|
||||||
return items
|
return items
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def bones_item(self,context):
|
|
||||||
|
def bones_item(self, context):
|
||||||
items = []
|
items = []
|
||||||
|
|
||||||
if context.scene.rig_picker.rig:
|
if context.scene.rig_picker.rig:
|
||||||
for bone in context.scene.rig_picker.rig.pose.bones:
|
for bone in context.scene.rig_picker.rig.pose.bones:
|
||||||
items.append((bone.name,bone.name,''))
|
items.append((bone.name, bone.name, ""))
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
class RP_PG_picker_source(bpy.types.PropertyGroup):
|
class RP_PG_picker_source(bpy.types.PropertyGroup):
|
||||||
source : StringProperty(subtype='FILE_PATH')
|
source: StringProperty(subtype="FILE_PATH")
|
||||||
|
|
||||||
|
|
||||||
class RP_PG_armature_ui_settings(bpy.types.PropertyGroup):
|
class RP_PG_armature_ui_settings(bpy.types.PropertyGroup):
|
||||||
name: StringProperty()
|
name: StringProperty()
|
||||||
source: StringProperty(subtype='FILE_PATH')
|
source: StringProperty(subtype="FILE_PATH")
|
||||||
sources: CollectionProperty(type=RP_PG_picker_source)
|
sources: CollectionProperty(type=RP_PG_picker_source)
|
||||||
|
|
||||||
|
|
||||||
class RP_PG_object_ui_settings(bpy.types.PropertyGroup):
|
class RP_PG_object_ui_settings(bpy.types.PropertyGroup):
|
||||||
shape_type: EnumProperty(items=[(i.upper(), i, "") for i in ('Bone', 'Display', 'Operator')])
|
shape_type: EnumProperty(
|
||||||
#idname: StringProperty()
|
items=[(i.upper(), i, "") for i in ("Bone", "Display", "Operator")]
|
||||||
#arguments: StringProperty()
|
)
|
||||||
|
# idname: StringProperty()
|
||||||
|
# arguments: StringProperty()
|
||||||
operator: StringProperty()
|
operator: StringProperty()
|
||||||
shortcut: StringProperty()
|
shortcut: StringProperty()
|
||||||
name: StringProperty()
|
name: StringProperty()
|
||||||
|
|
||||||
|
|
||||||
class RP_PG_collection_ui_settings(bpy.types.PropertyGroup):
|
class RP_PG_collection_ui_settings(bpy.types.PropertyGroup):
|
||||||
enabled : BoolProperty(default=False)
|
enabled: BoolProperty(default=False)
|
||||||
rig: PointerProperty(type=bpy.types.Object)
|
rig: PointerProperty(type=bpy.types.Object)
|
||||||
canvas: PointerProperty(type=bpy.types.Object)
|
canvas: PointerProperty(type=bpy.types.Object)
|
||||||
symmetry: PointerProperty(type=bpy.types.Object)
|
symmetry: PointerProperty(type=bpy.types.Object)
|
||||||
destination: StringProperty(subtype='FILE_PATH')
|
destination: StringProperty(subtype="FILE_PATH")
|
||||||
use_pick_bone : BoolProperty(default=False)
|
use_pick_bone: BoolProperty(default=False)
|
||||||
link_shape : BoolProperty(default=False)
|
link_shape: BoolProperty(default=False)
|
||||||
|
|
||||||
|
|
||||||
class RP_PG_scene_ui_settings(bpy.types.PropertyGroup):
|
class RP_PG_scene_ui_settings(bpy.types.PropertyGroup):
|
||||||
use_pick_bone : BoolProperty(default=False)
|
use_pick_bone: BoolProperty(default=False)
|
||||||
|
|
||||||
|
|
||||||
class RP_OT_operator_selector(bpy.types.Operator):
|
class RP_OT_operator_selector(bpy.types.Operator):
|
||||||
bl_label = "Select function"
|
bl_label = "Select function"
|
||||||
bl_idname = "rigpicker.operator_selector"
|
bl_idname = "rigpicker.operator_selector"
|
||||||
bl_property = "idname"
|
bl_property = "idname"
|
||||||
#bl_options = {'REGISTER', 'UNDO'}
|
# bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
idname: EnumProperty(items=[])
|
idname: EnumProperty(items=[])
|
||||||
|
|
||||||
@ -70,12 +79,12 @@ class RP_OT_operator_selector(bpy.types.Operator):
|
|||||||
ob = context.object
|
ob = context.object
|
||||||
ob.rig_picker.idname = self.idname
|
ob.rig_picker.idname = self.idname
|
||||||
context.area.tag_redraw()
|
context.area.tag_redraw()
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
wm.invoke_search_popup(self)
|
wm.invoke_search_popup(self)
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
@ -87,15 +96,23 @@ classes = (
|
|||||||
RP_OT_operator_selector,
|
RP_OT_operator_selector,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
bpy.types.Armature.rig_picker = bpy.props.PointerProperty(type=RP_PG_armature_ui_settings)
|
bpy.types.Armature.rig_picker = bpy.props.PointerProperty(
|
||||||
bpy.types.Object.rig_picker = bpy.props.PointerProperty(type=RP_PG_object_ui_settings)
|
type=RP_PG_armature_ui_settings
|
||||||
bpy.types.Collection.rig_picker = bpy.props.PointerProperty(type=RP_PG_collection_ui_settings)
|
)
|
||||||
|
bpy.types.Object.rig_picker = bpy.props.PointerProperty(
|
||||||
|
type=RP_PG_object_ui_settings
|
||||||
|
)
|
||||||
|
bpy.types.Collection.rig_picker = bpy.props.PointerProperty(
|
||||||
|
type=RP_PG_collection_ui_settings
|
||||||
|
)
|
||||||
bpy.types.Scene.rig_picker = bpy.props.PointerProperty(type=RP_PG_scene_ui_settings)
|
bpy.types.Scene.rig_picker = bpy.props.PointerProperty(type=RP_PG_scene_ui_settings)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
del bpy.types.Scene.rig_picker
|
del bpy.types.Scene.rig_picker
|
||||||
del bpy.types.Collection.rig_picker
|
del bpy.types.Collection.rig_picker
|
||||||
@ -104,4 +121,3 @@ def unregister():
|
|||||||
|
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
||||||
|
|||||||
13
pyproject.toml
Normal file
13
pyproject.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[project]
|
||||||
|
name = "rig-picker"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"black>=25.11.0",
|
||||||
|
"fake-bpy-module>=20251003",
|
||||||
|
]
|
||||||
@ -2,11 +2,11 @@
|
|||||||
flat in vec2 startPos;
|
flat in vec2 startPos;
|
||||||
in vec2 vertPos;
|
in vec2 vertPos;
|
||||||
|
|
||||||
out vec4 fragColor;
|
// out vec4 fragColor;
|
||||||
|
|
||||||
uniform vec4 color;
|
// uniform vec4 color;
|
||||||
uniform float dashSize;
|
// uniform float dashSize;
|
||||||
uniform float gapSize;
|
// uniform float gapSize;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@ -16,4 +16,4 @@ void main()
|
|||||||
if (fract(dist / (dashSize + gapSize)) > dashSize/(dashSize + gapSize))
|
if (fract(dist / (dashSize + gapSize)) > dashSize/(dashSize + gapSize))
|
||||||
discard;
|
discard;
|
||||||
fragColor = color;
|
fragColor = color;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
layout (location = 0) in vec2 pos;
|
// layout (location = 0) in vec2 pos;
|
||||||
|
|
||||||
flat out vec2 startPos;
|
flat out vec2 startPos;
|
||||||
out vec2 vertPos;
|
out vec2 vertPos;
|
||||||
|
|
||||||
uniform mat4 viewMatrix;
|
// uniform mat4 viewMatrix;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@ -12,4 +12,4 @@ void main()
|
|||||||
gl_Position = outPos;
|
gl_Position = outPos;
|
||||||
vertPos = pos.xy / outPos.w;
|
vertPos = pos.xy / outPos.w;
|
||||||
startPos = vertPos;
|
startPos = vertPos;
|
||||||
}
|
}
|
||||||
|
|||||||
152
ui.py
152
ui.py
@ -1,7 +1,8 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import UIList
|
from bpy.types import UIList
|
||||||
#import collections
|
|
||||||
#import inspect
|
# import collections
|
||||||
|
# import inspect
|
||||||
from .core.addon_utils import get_operator_from_id, get_picker_collection
|
from .core.addon_utils import get_operator_from_id, get_picker_collection
|
||||||
from .core.bl_utils import get_mat
|
from .core.bl_utils import get_mat
|
||||||
|
|
||||||
@ -20,17 +21,19 @@ import re
|
|||||||
|
|
||||||
|
|
||||||
class RP_PT_picker_maker_panel(bpy.types.Panel):
|
class RP_PT_picker_maker_panel(bpy.types.Panel):
|
||||||
bl_label = 'Rig Picker'
|
bl_label = "Rig Picker"
|
||||||
bl_category = 'Rigging'
|
bl_category = "Rigging"
|
||||||
bl_space_type = 'VIEW_3D'
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = 'UI'
|
bl_region_type = "UI"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.object
|
return context.object
|
||||||
|
|
||||||
def draw_header_preset(self, context):
|
def draw_header_preset(self, context):
|
||||||
self.layout.operator('rigpicker.add_picker_collection', text="", icon='ADD', emboss=False)
|
self.layout.operator(
|
||||||
|
"rigpicker.add_picker_collection", text="", icon="ADD", emboss=False
|
||||||
|
)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
@ -41,11 +44,15 @@ class RP_PT_picker_maker_panel(bpy.types.Panel):
|
|||||||
col = layout.column(align=False)
|
col = layout.column(align=False)
|
||||||
|
|
||||||
if collection:
|
if collection:
|
||||||
col.prop_search(collection.rig_picker, 'rig', scn, 'objects', text='Rig ')
|
col.prop_search(collection.rig_picker, "rig", scn, "objects", text="Rig ")
|
||||||
col.prop_search(collection.rig_picker, 'canvas', scn, 'objects', text='Canvas ')
|
col.prop_search(
|
||||||
col.prop_search(collection.rig_picker, 'symmetry', scn, 'objects', text='Symmetry ')
|
collection.rig_picker, "canvas", scn, "objects", text="Canvas "
|
||||||
|
)
|
||||||
|
col.prop_search(
|
||||||
|
collection.rig_picker, "symmetry", scn, "objects", text="Symmetry "
|
||||||
|
)
|
||||||
|
|
||||||
if ob.type == 'ARMATURE':
|
if ob.type == "ARMATURE":
|
||||||
box = col.box()
|
box = col.box()
|
||||||
box.enabled = not ob.data.library
|
box.enabled = not ob.data.library
|
||||||
col = box.column(align=False)
|
col = box.column(align=False)
|
||||||
@ -54,27 +61,41 @@ class RP_PT_picker_maker_panel(bpy.types.Panel):
|
|||||||
row.separator(factor=0.5)
|
row.separator(factor=0.5)
|
||||||
row.label(text="Sources")
|
row.label(text="Sources")
|
||||||
|
|
||||||
is_packed = ('pickers' in ob.data.rig_picker.keys())
|
is_packed = "pickers" in ob.data.rig_picker.keys()
|
||||||
row.operator('rigpicker.pack_picker', icon='PACKAGE' if is_packed else 'UGLYPACKAGE', text='', emboss=False)
|
row.operator(
|
||||||
row.operator("rigpicker.add_picker_source", icon ='ADD', text="", emboss=False)
|
"rigpicker.pack_picker",
|
||||||
|
icon="PACKAGE" if is_packed else "UGLYPACKAGE",
|
||||||
|
text="",
|
||||||
|
emboss=False,
|
||||||
|
)
|
||||||
|
row.operator(
|
||||||
|
"rigpicker.add_picker_source", icon="ADD", text="", emboss=False
|
||||||
|
)
|
||||||
|
|
||||||
for i, item in enumerate(ob.data.rig_picker.sources):
|
for i, item in enumerate(ob.data.rig_picker.sources):
|
||||||
row = col.row(align=True)
|
row = col.row(align=True)
|
||||||
row.enabled = not is_packed
|
row.enabled = not is_packed
|
||||||
row.prop(item, 'source', text='')
|
row.prop(item, "source", text="")
|
||||||
row.operator("rigpicker.remove_picker_source", icon ='PANEL_CLOSE', text="", emboss=False).index=i
|
row.operator(
|
||||||
|
"rigpicker.remove_picker_source",
|
||||||
|
icon="PANEL_CLOSE",
|
||||||
|
text="",
|
||||||
|
emboss=False,
|
||||||
|
).index = i
|
||||||
|
|
||||||
if collection:
|
if collection:
|
||||||
#layout.separator()
|
# layout.separator()
|
||||||
layout.prop(collection.rig_picker, 'destination', text='Filepath')
|
layout.prop(collection.rig_picker, "destination", text="Filepath")
|
||||||
layout.operator('rigpicker.save_picker', icon='PASTEDOWN', text='Save Picker')
|
layout.operator(
|
||||||
|
"rigpicker.save_picker", icon="PASTEDOWN", text="Save Picker"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RP_PT_shape(bpy.types.Panel):
|
class RP_PT_shape(bpy.types.Panel):
|
||||||
bl_label = 'Shape'
|
bl_label = "Shape"
|
||||||
bl_category = 'Rigging'
|
bl_category = "Rigging"
|
||||||
bl_space_type = 'VIEW_3D'
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = 'UI'
|
bl_region_type = "UI"
|
||||||
bl_parent_id = "RP_PT_picker_maker_panel"
|
bl_parent_id = "RP_PT_picker_maker_panel"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
@ -86,63 +107,92 @@ class RP_PT_shape(bpy.types.Panel):
|
|||||||
col = layout.column(align=False)
|
col = layout.column(align=False)
|
||||||
|
|
||||||
if collection:
|
if collection:
|
||||||
#if context.collection and context.collection.rig_picker.enabled:
|
# if context.collection and context.collection.rig_picker.enabled:
|
||||||
col = layout.column(align=True)
|
col = layout.column(align=True)
|
||||||
row = col.row(align=True)
|
row = col.row(align=True)
|
||||||
row.operator('rigpicker.create_shape', icon='MESH_DATA', text='Create Shape')
|
row.operator(
|
||||||
row.operator('rigpicker.mirror_shape', icon='MOD_MIRROR', text='Mirror Shape')
|
"rigpicker.create_shape", icon="MESH_DATA", text="Create Shape"
|
||||||
col.prop(scn.rig_picker, 'use_pick_bone', icon='EYEDROPPER', text='Auto Bone Assign')
|
)
|
||||||
col.operator('rigpicker.name_from_bone', icon='SORTALPHA' , text='Name From Bones')
|
row.operator(
|
||||||
|
"rigpicker.mirror_shape", icon="MOD_MIRROR", text="Mirror Shape"
|
||||||
|
)
|
||||||
|
col.prop(
|
||||||
|
scn.rig_picker,
|
||||||
|
"use_pick_bone",
|
||||||
|
icon="EYEDROPPER",
|
||||||
|
text="Auto Bone Assign",
|
||||||
|
)
|
||||||
|
col.operator(
|
||||||
|
"rigpicker.name_from_bone", icon="SORTALPHA", text="Name From Bones"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
col = layout.column(align=True)
|
col = layout.column(align=True)
|
||||||
row = col.row(align=True)
|
row = col.row(align=True)
|
||||||
row.operator('rigpicker.create_shape', icon='MESH_DATA', text='Create Shape')
|
row.operator(
|
||||||
|
"rigpicker.create_shape", icon="MESH_DATA", text="Create Shape"
|
||||||
|
)
|
||||||
|
|
||||||
if ob.type != 'ARMATURE':
|
if ob.type != "ARMATURE":
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
col = box.column(align=False)
|
col = box.column(align=False)
|
||||||
|
|
||||||
material_row = col.row(align=True)
|
material_row = col.row(align=True)
|
||||||
material_row.operator('rigpicker.remove_mat', icon='REMOVE', text='')
|
material_row.operator("rigpicker.remove_mat", icon="REMOVE", text="")
|
||||||
material_row.operator('rigpicker.add_mat', icon='ADD', text='')
|
material_row.operator("rigpicker.add_mat", icon="ADD", text="")
|
||||||
mat = False
|
mat = False
|
||||||
if ob.type in ('MESH', 'CURVE', 'FONT') and ob.data.materials:
|
if ob.type in ("MESH", "CURVE", "FONT") and ob.data.materials:
|
||||||
mat = get_mat(ob)
|
mat = get_mat(ob)
|
||||||
if mat and mat.node_tree:
|
if mat and mat.node_tree:
|
||||||
emission_nodes = [n for n in mat.node_tree.nodes if n.type =='EMISSION']
|
emission_nodes = [
|
||||||
|
n for n in mat.node_tree.nodes if n.type == "EMISSION"
|
||||||
|
]
|
||||||
if emission_nodes:
|
if emission_nodes:
|
||||||
material_row.prop(emission_nodes[0].inputs[0], 'default_value', text='')
|
material_row.prop(
|
||||||
|
emission_nodes[0].inputs[0], "default_value", text=""
|
||||||
|
)
|
||||||
mat = True
|
mat = True
|
||||||
if not mat:
|
if not mat:
|
||||||
material_row.label(text='No Material')
|
material_row.label(text="No Material")
|
||||||
material_row.operator('rigpicker.eyedropper_mat', icon='EYEDROPPER', text='')
|
material_row.operator(
|
||||||
|
"rigpicker.eyedropper_mat", icon="EYEDROPPER", text=""
|
||||||
|
)
|
||||||
|
|
||||||
shape_type_row = col.row(align=True)
|
shape_type_row = col.row(align=True)
|
||||||
shape_type_row.prop(ob.rig_picker,'shape_type',expand = True)
|
shape_type_row.prop(ob.rig_picker, "shape_type", expand=True)
|
||||||
shape_type_row.operator('rigpicker.select_shape_type', text='', icon='RESTRICT_SELECT_OFF')
|
shape_type_row.operator(
|
||||||
|
"rigpicker.select_shape_type", text="", icon="RESTRICT_SELECT_OFF"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ob.rig_picker.shape_type == "OPERATOR":
|
||||||
|
|
||||||
if ob.rig_picker.shape_type == 'OPERATOR':
|
|
||||||
|
|
||||||
op_row = col.row(align=True)
|
op_row = col.row(align=True)
|
||||||
op_row.prop(ob.rig_picker, 'operator', text='')
|
op_row.prop(ob.rig_picker, "operator", text="")
|
||||||
op_row.operator('rigpicker.operator_selector', text='', icon='COLLAPSEMENU')
|
op_row.operator(
|
||||||
|
"rigpicker.operator_selector", text="", icon="COLLAPSEMENU"
|
||||||
|
)
|
||||||
|
|
||||||
if ob.rig_picker.operator:
|
if ob.rig_picker.operator:
|
||||||
col.prop(ob.rig_picker, 'name', text='Tooltip')
|
col.prop(ob.rig_picker, "name", text="Tooltip")
|
||||||
col.prop(ob.rig_picker,'shortcut', text='Shortcut')
|
col.prop(ob.rig_picker, "shortcut", text="Shortcut")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
col.prop(ob.rig_picker, 'name', text='Tooltip')
|
col.prop(ob.rig_picker, "name", text="Tooltip")
|
||||||
|
|
||||||
elif ob.rig_picker.shape_type == 'BONE':
|
elif ob.rig_picker.shape_type == "BONE":
|
||||||
if collection and collection.rig_picker.rig:
|
if collection and collection.rig_picker.rig:
|
||||||
col.prop_search(ob.rig_picker, 'name', collection.rig_picker.rig.pose, 'bones', text='Bone')
|
col.prop_search(
|
||||||
|
ob.rig_picker,
|
||||||
|
"name",
|
||||||
|
collection.rig_picker.rig.pose,
|
||||||
|
"bones",
|
||||||
|
text="Bone",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
#RP_UL_picker_source,
|
# RP_UL_picker_source,
|
||||||
RP_PT_picker_maker_panel,
|
RP_PT_picker_maker_panel,
|
||||||
RP_PT_shape
|
RP_PT_shape,
|
||||||
)
|
)
|
||||||
|
|
||||||
register, unregister = bpy.utils.register_classes_factory(classes)
|
register, unregister = bpy.utils.register_classes_factory(classes)
|
||||||
|
|||||||
126
uv.lock
generated
Normal file
126
uv.lock
generated
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "black"
|
||||||
|
version = "25.11.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "mypy-extensions" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pathspec" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "pytokens" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831, upload-time = "2025-11-10T02:03:47Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520, upload-time = "2025-11-10T01:58:46.895Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719, upload-time = "2025-11-10T01:56:55.24Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684, upload-time = "2025-11-10T01:57:07.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446, upload-time = "2025-11-10T02:02:16.181Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983, upload-time = "2025-11-10T02:02:52.502Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481, upload-time = "2025-11-10T01:57:12.35Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869, upload-time = "2025-11-10T01:58:24.608Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358, upload-time = "2025-11-10T02:03:33.331Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902, upload-time = "2025-11-10T01:59:33.382Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571, upload-time = "2025-11-10T01:57:04.239Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599, upload-time = "2025-11-10T01:57:57.427Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918, upload-time = "2025-11-10T01:53:48.917Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fake-bpy-module"
|
||||||
|
version = "20251003"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3a/d7/8e34a795715d18497a257929ace8776a94d6c2c744e36b61e75567cbda64/fake_bpy_module-20251003.tar.gz", hash = "sha256:43d7fd082efc34497e238de3ad4d31fb850f2d1a8bb07418ae36eae56c1c7434", size = 973644, upload-time = "2025-10-03T06:19:57.638Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/24/d318f51ae1ebe953038984ed26fa0f9cd5466ef83da30c317282645695ec/fake_bpy_module-20251003-py3-none-any.whl", hash = "sha256:424f75fee6f300fc6d8e0d39abb28dbccd8777f611afa47ecdb9a03c00f2f43f", size = 1103011, upload-time = "2025-10-03T06:19:55.524Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mypy-extensions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathspec"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "4.5.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytokens"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rig-picker"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "." }
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "black" },
|
||||||
|
{ name = "fake-bpy-module" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [
|
||||||
|
{ name = "black", specifier = ">=25.11.0" },
|
||||||
|
{ name = "fake-bpy-module", specifier = ">=20251003" },
|
||||||
|
]
|
||||||
Loading…
x
Reference in New Issue
Block a user