Parent epic: #554
Goal
Direct bone-level CRUD on the skeleton of a selected entity: create a new bone (under a chosen parent), remove a bone (with optional weight transfer to parent), rename, duplicate. The user-requested foundation that every other slice depends on.
Scope
- New singleton
SkeletonEditor (src/SkeletonEditor.{h,cpp}) — main-thread, getSingleton/kill, signals boneCreated(name), boneRemoved(name), boneRenamed(old,new).
- Create bone:
- Pick parent bone in the inspector or right-click on a bone in the viewport.
- Default placement: at parent's tail, oriented along parent's axis. User can drag with
TransformOperator immediately after creation.
- Auto-name:
Bone, Bone.001, Bone.002 (Blender convention).
- Remove bone:
- Confirmation prompt if the bone has children (offer "remove with children" vs "promote children to parent").
- Weight transfer: any vertex weighted to the removed bone gets its weight reassigned to the parent (renormalized). Toggle for "transfer to parent" vs "drop weight".
- Refresh every
SubMesh::getBoneAssignments referencing the removed handle.
- Rename bone: inline edit in the outliner or context menu. Must propagate to:
- Every animation track in every clip that references the bone (
AnimationMerger-style renaming).
- Every
VertexBoneAssignment (handle stays the same; only the name field changes — Ogre stores by handle).
- The QML inspector / weight overlay caches.
- Duplicate bone: clones name (with
.001 suffix), TRS, parent. Does not clone children (different operation; covered in Slice B's "split chain").
- Undo: new commands
CreateBoneCommand, RemoveBoneCommand, RenameBoneCommand, DuplicateBoneCommand. Each rebuilds the affected vertex assignments + animation tracks atomically.
- Ogre quirk: there's no
Skeleton::removeBone. Bone deletion walks the bone list, rebuilds handles via Skeleton::_buildMapBoneByHandle, then rewrites every SubMesh::clearBoneAssignments / addBoneAssignment referencing the moved handles. Treat as the most complex op in this slice.
Acceptance Criteria
Effort
~9 days. Bone removal's handle-rebuild is the schedule risk.
Parent epic: #554
Goal
Direct bone-level CRUD on the skeleton of a selected entity: create a new bone (under a chosen parent), remove a bone (with optional weight transfer to parent), rename, duplicate. The user-requested foundation that every other slice depends on.
Scope
SkeletonEditor(src/SkeletonEditor.{h,cpp}) — main-thread,getSingleton/kill, signalsboneCreated(name),boneRemoved(name),boneRenamed(old,new).TransformOperatorimmediately after creation.Bone,Bone.001,Bone.002(Blender convention).SubMesh::getBoneAssignmentsreferencing the removed handle.AnimationMerger-style renaming).VertexBoneAssignment(handle stays the same; only the name field changes — Ogre stores by handle)..001suffix), TRS, parent. Does not clone children (different operation; covered in Slice B's "split chain").CreateBoneCommand,RemoveBoneCommand,RenameBoneCommand,DuplicateBoneCommand. Each rebuilds the affected vertex assignments + animation tracks atomically.Skeleton::removeBone. Bone deletion walks the bone list, rebuilds handles viaSkeleton::_buildMapBoneByHandle, then rewrites everySubMesh::clearBoneAssignments/addBoneAssignmentreferencing the moved handles. Treat as the most complex op in this slice.Acceptance Criteria
SkeletonDebugoverlay; drag with the gizmo works..001suffix.BoneDragRelease's drag-with-auto-key path.scene.skel.bone.create,.remove,.rename,.duplicate.Effort
~9 days. Bone removal's handle-rebuild is the schedule risk.