Skip to content

Commit f2d594b

Browse files
authored
Merge pull request #227 from WolvenKit/add-armature-utility-functions
added "delete unused bones" to animation tools
2 parents 2e494fa + 70a1ce1 commit f2d594b

File tree

6 files changed

+287
-228
lines changed

6 files changed

+287
-228
lines changed

i_scene_cp77_gltf/animtools/__init__.py

Lines changed: 113 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -33,100 +33,106 @@ class CP77_PT_AnimsPanel(Panel):
3333
def poll(cls, context):
3434
cp77_addon_prefs = bpy.context.preferences.addons['i_scene_cp77_gltf'].preferences
3535
if cp77_addon_prefs.context_only:
36-
return context.active_object and context.active_object.type == 'ARMATURE'
36+
return context.active_object and context.active_object.type == 'ARMATURE'
3737
else:
3838
return context
39-
40-
## make sure the context is unrestricted as possible, ensure there's an armature selected
39+
40+
## make sure the context is unrestricted as possible, ensure there's an armature selected
4141
def draw(self, context):
42-
layout = self.layout
42+
layout = self.layout
4343

4444
cp77_addon_prefs = bpy.context.preferences.addons['i_scene_cp77_gltf'].preferences
45-
46-
if cp77_addon_prefs.show_animtools:
47-
props = context.scene.cp77_panel_props
45+
46+
if not cp77_addon_prefs.show_animtools:
47+
return
48+
props = context.scene.cp77_panel_props
49+
box = layout.box()
50+
box.label(text='Rigs', icon_value=get_icon("WKIT"))
51+
row = box.row(align=True)
52+
row.operator('cp77.rig_loader', text="Load Bundled Rig")
53+
obj = context.active_object
54+
55+
if obj is None or obj.type != 'ARMATURE':
56+
return
57+
58+
col = box.column()
59+
if 'deformBonesHidden' in obj:
60+
col.operator('bone_unhider.cp77',text='Unhide Deform Bones')
61+
else:
62+
col.operator('bone_hider.cp77',text='Hide Deform Bones')
63+
col.operator('reset_armature.cp77')
64+
col.operator('delete_unused_bones.cp77', text='Delete unused bones')
65+
col.operator('cp77.anim_namer')
66+
available_anims = list(CP77AnimsList(context,obj))
67+
active_action = obj.animation_data.action if obj.animation_data else None
68+
if not available_anims:
4869
box = layout.box()
49-
box.label(text='Rigs', icon_value=get_icon("WKIT"))
5070
row = box.row(align=True)
51-
row.operator('cp77.rig_loader', text="Load Bundled Rig")
52-
obj = context.active_object
53-
if obj and obj.type == 'ARMATURE':
54-
col = box.column()
55-
if 'deformBonesHidden' in obj:
56-
col.operator('bone_unhider.cp77',text='Unhide Deform Bones')
57-
else:
58-
col.operator('bone_hider.cp77',text='Hide Deform Bones')
59-
col.operator('reset_armature.cp77')
60-
col.operator('cp77.anim_namer')
61-
available_anims = list(CP77AnimsList(context,obj))
62-
active_action = obj.animation_data.action if obj.animation_data else None
63-
if not available_anims:
64-
box = layout.box()
65-
row = box.row(align=True)
66-
row.label(text='Animsets', icon_value=get_icon("WKIT"))
67-
row.operator('cp77.new_action',icon='ADD', text="")
68-
row = box.row(align=True)
69-
row.menu('RENDER_MT_framerate_presets')
70-
row = box.row(align=True)
71-
row.prop(context.scene.render, "fps")
72-
row.prop(context.scene.render, "fps_base")
73-
row = box.row(align=True)
74-
row.operator('insert_keyframe.cp77')
75-
76-
if available_anims:
77-
box = layout.box()
78-
for action in available_anims:
79-
action.use_fake_user:True
80-
selected = action == active_action
81-
if selected:
82-
row = box.row(align=True)
83-
row.alignment='CENTER'
84-
row.operator("screen.frame_jump", text="", icon='REW').end = False
85-
row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False
86-
row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
87-
row.operator("screen.animation_play", text="", icon='PLAY')
88-
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
89-
row.operator("screen.frame_jump", text="", icon='FF').end = True
90-
row = box.row(align=True)
91-
row.prop(active_action, 'use_frame_range', text="Set Playback Range",toggle=1)
92-
if active_action.use_frame_range:
93-
row = box.row(align=True)
94-
row.prop(bpy.context.scene, 'frame_start', text="")
95-
row.prop(bpy.context.scene, 'frame_end', text="")
96-
97-
box = layout.box()
98-
row = box.row(align=True)
99-
row.label(text='Animsets', icon_value=get_icon('WKIT'))
100-
row.operator('cp77.new_action',icon='ADD', text="")
101-
row = box.row(align=True)
102-
row.menu('RENDER_MT_framerate_presets')
103-
row = box.row(align=True)
104-
row.prop(context.scene.render, "fps")
105-
row.prop(context.scene.render, "fps_base")
71+
row.label(text='Animsets', icon_value=get_icon("WKIT"))
72+
row.operator('cp77.new_action',icon='ADD', text="")
73+
row = box.row(align=True)
74+
row.menu('RENDER_MT_framerate_presets')
75+
row = box.row(align=True)
76+
row.prop(context.scene.render, "fps")
77+
row.prop(context.scene.render, "fps_base")
78+
row = box.row(align=True)
79+
row.operator('insert_keyframe.cp77')
80+
return
81+
82+
83+
box = layout.box()
84+
for action in available_anims:
85+
action.use_fake_user:True
86+
selected = action == active_action
87+
if selected:
88+
row = box.row(align=True)
89+
row.alignment='CENTER'
90+
row.operator("screen.frame_jump", text="", icon='REW').end = False
91+
row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False
92+
row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
93+
row.operator("screen.animation_play", text="", icon='PLAY')
94+
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
95+
row.operator("screen.frame_jump", text="", icon='FF').end = True
96+
row = box.row(align=True)
97+
row.prop(active_action, 'use_frame_range', text="Set Playback Range",toggle=1)
98+
if active_action.use_frame_range:
10699
row = box.row(align=True)
107-
row.operator('insert_keyframe.cp77')
108-
# if available_anims:
109-
col = box.column(align=True)
110-
for action in available_anims:
111-
action.use_fake_user:True
112-
selected = action == active_action
113-
row = col.row(align=True)
114-
sub = row.column(align=True)
115-
sub.ui_units_x = 1.0
116-
if selected and context.screen.is_animation_playing:
117-
op = sub.operator('screen.animation_cancel', icon='PAUSE', text=action.name, emboss=True)
118-
op.restore_frame = False
119-
if active_action.use_frame_range:
120-
row.prop(active_action, 'use_cyclic', icon='CON_FOLLOWPATH', text="")
121-
else:
122-
icon = 'PLAY' if selected else 'TRIA_RIGHT'
123-
op = sub.operator('cp77.set_animset', icon=icon, text="", emboss=True)
124-
op.name = action.name
125-
op.play = True
126-
op = row.operator('cp77.set_animset', text=action.name)
127-
op.name = action.name
128-
op.play = False
129-
row.operator('cp77.delete_anims', icon='X', text="").name = action.name
100+
row.prop(bpy.context.scene, 'frame_start', text="")
101+
row.prop(bpy.context.scene, 'frame_end', text="")
102+
103+
box = layout.box()
104+
row = box.row(align=True)
105+
row.label(text='Animsets', icon_value=get_icon('WKIT'))
106+
row.operator('cp77.new_action',icon='ADD', text="")
107+
row = box.row(align=True)
108+
row.menu('RENDER_MT_framerate_presets')
109+
row = box.row(align=True)
110+
row.prop(context.scene.render, "fps")
111+
row.prop(context.scene.render, "fps_base")
112+
row = box.row(align=True)
113+
row.operator('insert_keyframe.cp77')
114+
# if available_anims:
115+
col = box.column(align=True)
116+
for action in available_anims:
117+
action.use_fake_user:True
118+
selected = action == active_action
119+
row = col.row(align=True)
120+
sub = row.column(align=True)
121+
sub.ui_units_x = 1.0
122+
if selected and context.screen.is_animation_playing:
123+
op = sub.operator('screen.animation_cancel', icon='PAUSE', text=action.name, emboss=True)
124+
op.restore_frame = False
125+
if active_action.use_frame_range:
126+
row.prop(active_action, 'use_cyclic', icon='CON_FOLLOWPATH', text="")
127+
else:
128+
icon = 'PLAY' if selected else 'TRIA_RIGHT'
129+
op = sub.operator('cp77.set_animset', icon=icon, text="", emboss=True)
130+
op.name = action.name
131+
op.play = True
132+
op = row.operator('cp77.set_animset', text=action.name)
133+
op.name = action.name
134+
op.play = False
135+
row.operator('cp77.delete_anims', icon='X', text="").name = action.name
130136

131137

132138
### allow deleting animations from the animset panel, regardless of editor context
@@ -147,7 +153,7 @@ def execute(self, context):
147153
return{'FINISHED'}
148154

149155

150-
# this class is where most of the function is so far - play/pause
156+
# this class is where most of the function is so far - play/pause
151157
# Todo: fix renaming actions from here
152158
class CP77Animset(Operator):
153159
bl_idname = 'cp77.set_animset'
@@ -206,7 +212,7 @@ class CP77BoneHider(Operator):
206212
bl_options = {'REGISTER', 'UNDO'}
207213
bl_label = "Toggle Deform Bone Visibilty"
208214
bl_description = "Hide deform bones in the selected armature"
209-
215+
210216
def execute(self, context):
211217
hide_extra_bones(self, context)
212218
return{'FINISHED'}
@@ -218,7 +224,7 @@ class CP77BoneUnhider(Operator):
218224
bl_options = {'REGISTER', 'UNDO'}
219225
bl_label = "Toggle Deform Bone Visibilty"
220226
bl_description = "Unhide deform bones in the selected armature"
221-
227+
222228
def execute(self, context):
223229
unhide_extra_bones(self, context)
224230
return{'FINISHED'}
@@ -238,7 +244,7 @@ def execute(self, context):
238244
props = context.scene.cp77_panel_props
239245
cp77_keyframe(props, context, props.frameall)
240246
return {"FINISHED"}
241-
247+
242248
def draw(self, context):
243249
layout = self.layout
244250
props = context.scene.cp77_panel_props
@@ -258,13 +264,23 @@ def execute(self, context):
258264
reset_armature(self, context)
259265
return {"FINISHED"}
260266

267+
class CP77DeleteUnusedBones(Operator):
268+
bl_idname = "delete_unused_bones.cp77"
269+
bl_parent_id = "CP77_PT_animspanel"
270+
bl_label = "Delete unused bones"
271+
bl_description = "Delete all bones that aren't used by meshes parented to the armature"
272+
273+
def execute(self, context):
274+
delete_unused_bones(self, context)
275+
return {"FINISHED"}
276+
261277

262278
class CP77NewAction(Operator):
263279

264280
bl_idname = 'cp77.new_action'
265281
bl_label = "Add Action"
266282
bl_options = {'INTERNAL', 'UNDO'}
267-
bl_description = "Add a new action to the list"
283+
bl_description = "Add a new action to the list"
268284

269285
name: StringProperty(default="New action")
270286

@@ -290,14 +306,14 @@ def invoke(self, context, event):
290306
class CP77RigLoader(Operator):
291307
bl_idname = "cp77.rig_loader"
292308
bl_label = "Load Deform Rig from Resources"
293-
bl_description = "Load Cyberpunk 2077 deform rigs from plugin resources"
309+
bl_description = "Load Cyberpunk 2077 deform rigs from plugin resources"
294310

295311
files: CollectionProperty(type=OperatorFileListElement)
296312
appearances: StringProperty(name="Appearances", default="")
297313
directory: StringProperty(name="Directory", default="")
298314
filepath: StringProperty(name="Filepath", default="")
299315
rigify_it: BoolProperty(name='Apply Rigify Rig', default=False)
300-
316+
301317
def invoke(self, context, event):
302318
return context.window_manager.invoke_props_dialog(self)
303319

@@ -310,14 +326,14 @@ def execute(self, context):
310326
# Find the corresponding .glb file and load it
311327
selected_rig = rig_files[rig_names.index(selected_rig_name)]
312328
self.filepath = selected_rig
313-
CP77GLBimport(self, exclude_unused_mats=True, image_format='PNG', with_materials=False,
329+
CP77GLBimport(self, exclude_unused_mats=True, image_format='PNG', with_materials=False,
314330
filepath=selected_rig, hide_armatures=False, import_garmentsupport=False, files=[], directory='', appearances="ALL", remap_depot=False)
315331
if props.fbx_rot:
316332
rotate_quat_180(self,context)
317333
if self.rigify_it:
318334
create_rigify_rig(self,context)
319335
return {'FINISHED'}
320-
336+
321337
def draw(self,context):
322338
props = context.scene.cp77_panel_props
323339
layout = self.layout
@@ -334,8 +350,8 @@ class CP77AnimNamer(Operator):
334350
bl_idname = "cp77.anim_namer"
335351
bl_label = "Fix Action Names"
336352
bl_options = {'INTERNAL', 'UNDO'}
337-
bl_description = "replace spaces and capital letters in animation names with underscores and lower case letters"
338-
353+
bl_description = "replace spaces and capital letters in animation names with underscores and lower case letters"
354+
339355
def execute(self, context):
340356
for a in CP77AnimsList(self,context): a.name = a.name.replace(" ", "_").lower()
341357
return {'FINISHED'}

0 commit comments

Comments
 (0)