Skip to content

Commit

Permalink
Improved add/edit custom bone dialog (#257)
Browse files Browse the repository at this point in the history
* Improved add-custom-bone dialog.

Added "parent bone" and "rotation" UI elements to the add-custom-bone
dialog (dlgCustomBone) and implemented them.

* Implemented edit-custom-bone dialog

-Added a menu option to the bone-tree context menu called "Edit Bone..."
that calls OutfitStudioFrame::OnEditBone.

-Only custom bones can be edited.  If a standard bone is selected,
the dialog is read-only.

Co-authored-by: ousnius <[email protected]>
  • Loading branch information
sts1skj and ousnius authored Mar 17, 2020
1 parent 1469600 commit 08190a1
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 62 deletions.
8 changes: 8 additions & 0 deletions res/xrc/OutfitStudio.xrc
Original file line number Diff line number Diff line change
Expand Up @@ -2182,6 +2182,10 @@
<help>Delete bone(s) from only the selected shapes.</help>
</object>
</object>
<object class="wxMenuItem" name="editBone">
<label>Edit Bone...</label>
<help>Edit a custom bone or view a standard bone.</help>
</object>
</object>
<object class="wxMenu" name="menuBoneTreeContext">
<label>Bones</label>
Expand All @@ -2196,6 +2200,10 @@
<help>Add a custom bone to the project.</help>
</object>
</object>
<object class="wxMenuItem" name="editBone">
<label>Edit Bone...</label>
<help>Edit a custom bone or view a standard bone.</help>
</object>
</object>
<object class="wxMenu" name="menuSegmentContext">
<label>Segments</label>
Expand Down
98 changes: 82 additions & 16 deletions res/xrc/Skeleton.xrc
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,20 @@
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticText" name="labelX">
<label>X</label>
<object class="wxStaticText" name="lbParentBone">
<label>Parent</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="textX">
<value>0.00000</value>
<object class="wxChoice" name="cParentBone">
<selection>0</selection>
<content />
</object>
</object>
</object>
Expand All @@ -108,8 +109,65 @@
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="wxFlexGridSizer">
<rows>0</rows>
<cols>3</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<growablecols>1</growablecols>
<growablerows></growablerows>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticText" name="labelblank">
<label></label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticText" name="labelorigin">
<label>Origin</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticText" name="labelrot">
<label>Rotation</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticText" name="labelX">
<label>X</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="textX">
<value>0.00000</value>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="textRX">
<value>0.00000</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
Expand All @@ -127,14 +185,14 @@
<value>0.00000</value>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="textRY">
<value>0.00000</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
Expand All @@ -152,6 +210,14 @@
<value>0.00000</value>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="textRZ">
<value>0.00000</value>
</object>
</object>
</object>
</object>
<object class="sizeritem">
Expand Down
44 changes: 34 additions & 10 deletions src/components/Anim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,7 @@ bool AnimInfo::AddShapeBone(const std::string& shape, const std::string& boneNam
shapeSkinning[shape].boneNames[boneName] = shapeBones[shape].size();
shapeBones[shape].push_back(boneName);
AnimSkeleton::getInstance().RefBone(boneName);
// Calculate a good default value for xformSkinToBone by:
// Composing: bone -> global -> skin
// then inverting
MatTransform xformGlobalToSkin = shapeSkinning[shape].xformGlobalToSkin;
MatTransform xformBoneToGlobal;
AnimSkeleton::getInstance().GetBoneTransformToGlobal(boneName, xformBoneToGlobal);
MatTransform xformBoneToSkin = xformGlobalToSkin.ComposeTransforms(xformBoneToGlobal);
SetXFormSkinToBone(shape, boneName, xformBoneToSkin.InverseTransform());
RecalcXFormSkinToBone(shape, boneName);
return true;
}

Expand Down Expand Up @@ -242,6 +235,23 @@ void AnimInfo::SetXFormSkinToBone(const std::string& shape, const std::string& b
shapeSkinning[shape].boneWeights[b].xformSkinToBone = stransform;
}

void AnimInfo::RecalcXFormSkinToBone(const std::string& shape, const std::string& boneName) {
// Calculate a good default value for xformSkinToBone by:
// Composing: bone -> global -> skin
// then inverting
MatTransform xformGlobalToSkin = shapeSkinning[shape].xformGlobalToSkin;
MatTransform xformBoneToGlobal;
AnimSkeleton::getInstance().GetBoneTransformToGlobal(boneName, xformBoneToGlobal);
MatTransform xformBoneToSkin = xformGlobalToSkin.ComposeTransforms(xformBoneToGlobal);
SetXFormSkinToBone(shape, boneName, xformBoneToSkin.InverseTransform());
}

void AnimInfo::RecursiveRecalcXFormSkinToBone(const std::string& shape, AnimBone *bPtr) {
RecalcXFormSkinToBone(shape, bPtr->boneName);
for (AnimBone *cptr : bPtr->children)
RecursiveRecalcXFormSkinToBone(shape, cptr);
}

bool AnimInfo::CalcShapeSkinBounds(const std::string& shapeName, const int& boneIndex) {
if (!refNif || !refNif->IsValid()) // Check for existence of reference nif
return false;
Expand Down Expand Up @@ -480,9 +490,8 @@ AnimBone *AnimSkeleton::LoadCustomBoneFromNif(NifFile *nif, const std::string &b
parentBone = LoadCustomBoneFromNif(nif, parentNode->GetName());
}
AnimBone& cstm = AnimSkeleton::getInstance().AddCustomBone(boneName);
cstm.parent = parentBone;
parentBone->children.push_back(&cstm);
cstm.SetTransformBoneToParent(node->GetTransformToParent());
cstm.SetParentBone(parentBone);
return &cstm;
}

Expand Down Expand Up @@ -594,3 +603,18 @@ void AnimBone::SetTransformBoneToParent(const MatTransform &ttp) {
UpdateTransformToGlobal();
UpdatePoseTransform();
}

void AnimBone::SetParentBone(AnimBone* newParent) {
if (parent == newParent)
return;
if (parent) {
//std::erase(parent->children, this);
auto it = std::remove(parent->children.begin(), parent->children.end(), this);
parent->children.erase(it, parent->children.end());
}
parent = newParent;
if (parent)
parent->children.push_back(this);
UpdateTransformToGlobal();
UpdatePoseTransform();
}
14 changes: 12 additions & 2 deletions src/components/Anim.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,17 @@ class AnimBone {
// and xformPoseToGlobal, for this and for descendants.
void SetTransformBoneToParent(const MatTransform &ttp);
// UpdateTransformToGlobal updates xformToGlobal for this and for
// descendants. This should only be called from itself and
// SetTransformBoneToParent.
// descendants. This should only be called from itself,
// SetTransformBoneToParent, and SetParentBone.
void UpdateTransformToGlobal();
// UpdatePoseTransform updates xformPoseToGlobal for this and all
// descendants. Call it after poseRotVec, poseTranVec, or
// xformToGlobal is changed.
void UpdatePoseTransform();
// SetParentBone updates "parent" of this and "children" of the old
// and new parents. It also calls UpdateTransformToGlobal and
// UpdatePoseTranform.
void SetParentBone(AnimBone* newParent);
};

// Vertex to weight value association. Also keeps track of skin-to-bone transform and bounding sphere.
Expand Down Expand Up @@ -146,6 +150,12 @@ class AnimInfo {
void SetWeights(const std::string& shape, const std::string& boneName, std::unordered_map<ushort, float>& inVertWeights);
bool GetXFormSkinToBone(const std::string& shape, const std::string& boneName, MatTransform& stransform);
void SetXFormSkinToBone(const std::string& shape, const std::string& boneName, const MatTransform& stransform);
// RecalcXFormSkinToBone recalculates a shape bone's xformSkinToBone
// from other transforms.
void RecalcXFormSkinToBone(const std::string& shape, const std::string& boneName);
// RecursiveRecalcXFormSkinToBone calls RecalcXFormSkinToBone for the
// given bone and all its descendants.
void RecursiveRecalcXFormSkinToBone(const std::string& shape, AnimBone *bPtr);
bool CalcShapeSkinBounds(const std::string& shapeName, const int& boneIndex);
void CleanupBones();
void WriteToNif(NifFile* nif, const std::string& shapeException = "");
Expand Down
15 changes: 10 additions & 5 deletions src/program/OutfitProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1755,16 +1755,21 @@ void OutfitProject::AddBoneRef(const std::string& boneName) {
workAnim.AddShapeBone(s, boneName);
}

void OutfitProject::AddCustomBoneRef(const std::string& boneName, const Vector3& translation) {
void OutfitProject::AddCustomBoneRef(const std::string& boneName, const std::string& parentBone, const MatTransform &xformToParent) {
AnimBone& customBone = AnimSkeleton::getInstance().AddCustomBone(boneName);
customBone.SetTransformBoneToParent(xformToParent);
customBone.SetParentBone(AnimSkeleton::getInstance().GetBonePtr(parentBone));

MatTransform xformBoneToGlobal;
xformBoneToGlobal.translation = translation;
for (auto &s : workNif.GetShapeNames())
workAnim.AddShapeBone(s, boneName);
}

customBone.SetTransformBoneToParent(xformBoneToGlobal);
void OutfitProject::ModifyCustomBone(AnimBone *bPtr, const std::string& parentBone, const MatTransform &xformToParent) {
bPtr->SetTransformBoneToParent(xformToParent);
bPtr->SetParentBone(AnimSkeleton::getInstance().GetBonePtr(parentBone));

for (auto &s : workNif.GetShapeNames())
workAnim.AddShapeBone(s, boneName);
workAnim.RecursiveRecalcXFormSkinToBone(s, bPtr);
}

void OutfitProject::ClearWorkSliders() {
Expand Down
3 changes: 2 additions & 1 deletion src/program/OutfitProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ class OutfitProject {
void ClearBoneScale(bool clear = true);

void AddBoneRef(const std::string& boneName);
void AddCustomBoneRef(const std::string& boneName, const Vector3& translation);
void AddCustomBoneRef(const std::string& boneName, const std::string& parentBone, const MatTransform &xformToParent);
void ModifyCustomBone(AnimBone *bPtr, const std::string& parentBone, const MatTransform &xformToParent);

void ClearWorkSliders();
void ClearReference();
Expand Down
Loading

0 comments on commit 08190a1

Please sign in to comment.