From 0e1283a4d7d75551c77a9e46d54b962e29f272e8 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Mon, 13 Jan 2025 02:53:33 +0100 Subject: [PATCH] Rework bone selection logic A skeleton no longer has a "selectedBone". It's all in the anim editor now. --- Aquaria/AnimationEditor.cpp | 145 +++++++++++++++++++++++++++--------- Aquaria/AnimationEditor.h | 3 + BBGE/SkeletalSprite.cpp | 95 ++++------------------- BBGE/SkeletalSprite.h | 11 +-- 4 files changed, 128 insertions(+), 126 deletions(-) diff --git a/Aquaria/AnimationEditor.cpp b/Aquaria/AnimationEditor.cpp index ccb822c..b09f42a 100644 --- a/Aquaria/AnimationEditor.cpp +++ b/Aquaria/AnimationEditor.cpp @@ -436,6 +436,8 @@ void AnimationEditor::applyState() editMode = AE_SELECT; editingBone = 0; editingBoneSprite = 0; + editingBonePage = -1; + editingBoneIdx = -1; currentKey = 0; splinegrid = 0; assistedSplineEdit = true; @@ -874,10 +876,9 @@ void AnimationEditor::toggleMouseSelection() { if (dsq->isNested()) return; - if (mouseSelection) + if (editingBone) { - for(size_t i = 0; i < NumPages; ++i) - getPageSprite(i)->updateSelectedBoneColor(); + editingBone->color = Vector(1,1,1); } mouseSelection = !mouseSelection; @@ -908,26 +909,6 @@ void AnimationEditor::moveBoneStripPoint(const Vector &mov) } } -void AnimationEditor::selectPrevBone() -{ - if (dsq->isNested()) return; - - if (editMode == AE_SELECT) - { - getCurrentPageSprite()->selectPrevBone(); - } -} - -void AnimationEditor::selectNextBone() -{ - if (dsq->isNested()) return; - - if (editMode == AE_SELECT) - { - getCurrentPageSprite()->selectNextBone(); - } -} - void AnimationEditor::update(float dt) { StateObject::update(dt); @@ -1199,17 +1180,17 @@ void AnimationEditor::nextKey() { if (dsq->isNested()) return; - SkeletalSprite *editSprite = getCurrentPageSprite(); - if (editMode == AE_STRIP) { selectedStripPoint++; - if (selectedStripPoint >= editingBoneSprite->getSelectedBone(false)->changeStrip.size() + if (selectedStripPoint >= editingBone->changeStrip.size() && selectedStripPoint > 0) selectedStripPoint --; } else { + SkeletalSprite *editSprite = getCurrentPageSprite(); + if (core->getCtrlState()) { const std::vector& keyframeWidgets = pages[curPage].timeline->getKeyframes(); @@ -1236,8 +1217,6 @@ void AnimationEditor::prevKey() { if (dsq->isNested()) return; - SkeletalSprite *editSprite = getCurrentPageSprite(); - if (editMode == AE_STRIP) { if(selectedStripPoint > 0) @@ -1245,6 +1224,8 @@ void AnimationEditor::prevKey() } else { + SkeletalSprite *editSprite = getCurrentPageSprite(); + if (core->getCtrlState()) { const std::vector& keyframeWidgets = pages[curPage].timeline->getKeyframes(); @@ -1743,6 +1724,7 @@ void AnimationEditor::loadFile(size_t pg, const char* fn) { SkeletalSprite::clearCache(); editingBone = 0; + editingBoneIdx = -1; pages[pg].clearUndoHistory(); //editSprite->position = Vector(0,0); pages[pg].load(fn); @@ -1958,9 +1940,14 @@ void AnimationEditor::updateEditingBone() if(!mouseSelection) { - editingBoneSprite = getCurrentPageSprite(); - editingBone = editingBoneSprite->getSelectedBone(false); + if(!editingBoneSprite) + editingBoneSprite = getCurrentPageSprite(); editingBonePage = curPage; + Bone *b = (size_t)editingBoneIdx < editingBoneSprite->bones.size() ? editingBoneSprite->bones[editingBoneIdx] : NULL; // this uses underflow at -1 + if(b && b->selectable) + _selectBone(b); + else + selectNextBone(); return; } @@ -1968,30 +1955,34 @@ void AnimationEditor::updateEditingBone() float mind; Bone *nearest = NULL; SkeletalSprite *nearestSpr = NULL; - const Vector p = core->mouse.position; - int page = -1; + const Vector& p = core->mouse.position; + int page = -1, idx = -1; for(size_t i = 0; i < NumPages; ++i) { SkeletalSprite& spr = pages[i].editSprite; if(spr.isLoaded()) { - if(Bone *b = spr.getSelectedBone(true)) + int k = spr.findSelectableBoneIdxClosestTo(p, true); + if(k >= 0) { - const float d = (b->position - p).getSquaredLength2D(); + Bone *b = spr.bones[k]; + const float d = (b->getWorldPosition() - p).getSquaredLength2D(); if(!nearest || d < mind) { mind = d; nearest = b; nearestSpr = &spr; page = i; + idx = k; } } } } - editingBone = nearest; editingBoneSprite = nearestSpr; editingBonePage = page; + editingBoneIdx = idx; + _selectBone(nearest); } void AnimationEditor::showAllBones() @@ -2065,6 +2056,8 @@ void AnimationEditor::updateButtonLabels() void AnimationEditor::toggleGradient() { + if (dsq->isNested()) return; + bgGrad->alpha.x = float(bgGrad->alpha.x <= 0); } @@ -2137,6 +2130,12 @@ void AnimationEditor::selectPage(unsigned page) if(editMode != AE_SELECT) return; + if(!mouseSelection) + { + editingBoneSprite = &pages[page].editSprite; + updateEditingBone(); + } + curPage = page; } @@ -2179,3 +2178,79 @@ void AnimationEditor::applySplineGridToBone() } } +void AnimationEditor::_selectBone(Bone *b) +{ + if(editingBone) + editingBone->color = Vector(1,1,1); + + if (b) + b->color = mouseSelection ? Vector(1,0,0) : Vector(0.5,0.5,1); + else + { + editingBonePage = -1; + editingBoneSprite = NULL; + editingBoneIdx = -1; + } + + editingBone = b; +} + +void AnimationEditor::selectPrevBone() +{ + if (dsq->isNested() || mouseSelection || editMode != AE_SELECT) + return; + + SkeletalSprite *spr = editingBoneSprite ? editingBoneSprite : getCurrentPageSprite(); + if(spr->bones.empty()) + return; + + size_t idx = editingBoneIdx; + Bone *b = NULL; + do + { + idx++; + if(idx == editingBoneIdx) + { + idx = -1; + break; + } + if (idx >= spr->bones.size()) + idx = 0; + b = spr->bones[idx]; + } + while (!b->selectable); + editingBoneIdx = idx; + editingBonePage = curPage; + editingBoneSprite = spr; + _selectBone(b); +} + +void AnimationEditor::selectNextBone() +{ + if (dsq->isNested() || mouseSelection || editMode != AE_SELECT) + return; + + SkeletalSprite *spr = editingBoneSprite ? editingBoneSprite : getCurrentPageSprite(); + if(spr->bones.empty()) + return; + + size_t idx = editingBoneIdx; + Bone *b = NULL; + do + { + idx--; + if(idx == editingBoneIdx) + { + idx = -1; + break; + } + if (idx >= spr->bones.size()) + idx = spr->bones.size()-1; + b = spr->bones[idx]; + } + while (!b->selectable); + editingBoneIdx = idx; + editingBonePage = curPage; + editingBoneSprite = spr; + _selectBone(b); +} diff --git a/Aquaria/AnimationEditor.h b/Aquaria/AnimationEditor.h index 55e7a46..9d38f04 100644 --- a/Aquaria/AnimationEditor.h +++ b/Aquaria/AnimationEditor.h @@ -100,6 +100,7 @@ public: Bone *editingBone; // only changed when editMode == AE_SELECT SkeletalSprite *editingBoneSprite; // updated together with editingBone int editingBonePage; + int editingBoneIdx; // editingBoneSprite->bones[editingBoneIdx] == editingBone EditMode editMode; DebugFont *text, *text2, *toptext, *btmtext; @@ -195,6 +196,8 @@ private: void reloadAll(); bool savePage(size_t pg); void reloadPage(size_t pg); + + void _selectBone(Bone *b); // NULL to unselect }; diff --git a/BBGE/SkeletalSprite.cpp b/BBGE/SkeletalSprite.cpp index 07d7bb3..71cbcf6 100644 --- a/BBGE/SkeletalSprite.cpp +++ b/BBGE/SkeletalSprite.cpp @@ -775,7 +775,6 @@ SkeletalSprite::SkeletalSprite() : RenderObject() animLayers.resize(10); for (size_t i = 0; i < animLayers.size(); i++) animLayers[i].setSkeletalSprite(this); - selectedBone = -1; } SkeletalSprite::~SkeletalSprite() @@ -2113,94 +2112,28 @@ void SkeletalSprite::setTimeMultiplier(float t, int layer) animLayers[layer].timeMultiplier = t; } -Bone* SkeletalSprite::getSelectedBone(bool mouseBased) +int SkeletalSprite::findSelectableBoneIdxClosestTo(const Vector& pos, bool mustBeInBox) const { - if (!loaded) return 0; - if (mouseBased) - { - float closestDist = HUGE_VALF; - Bone *b = 0; - Vector p = core->mouse.position; - for (size_t i = 0; i < bones.size(); i++) - { - if (bones[i]->renderQuad || core->getShiftState()) - { - bones[i]->color = Vector(1,1,1); - if (bones[i]->selectable && bones[i]->renderQuad && bones[i]->isCoordinateInsideWorld(p)) - { - float dist = (bones[i]->getWorldPosition() - p).getSquaredLength2D(); - if (dist <= closestDist) - { - closestDist = dist; - b = bones[i]; - selectedBone = i; - } - } - } - } - if (b) - { - b->color = Vector(1,0,0); - } - return b; - } - // else - if (!bones.empty() && selectedBone < bones.size()) - return bones[selectedBone]; - - return 0; -} - - -void SkeletalSprite::updateSelectedBoneColor() -{ - if(!bones.size()) - return; - + float closestDist = HUGE_VALF; + int idx = -1; for (size_t i = 0; i < bones.size(); i++) { - bones[i]->color = Vector(1,1,1); + Bone *b = bones[i]; + if (b->selectable && b->renderQuad && (!mustBeInBox || b->isCoordinateInsideWorld(pos))) + { + float dist = (b->getWorldPosition() - pos).getSquaredLength2D(); + if (dist <= closestDist) + { + closestDist = dist; + idx = (int)i; + } + } } - Bone *b = bones[selectedBone]; - if (b) - b->color = Vector(0.5,0.5,1); + return idx; } -void SkeletalSprite::setSelectedBone(int b) -{ - selectedBone = b; - updateSelectedBoneColor(); -} -void SkeletalSprite::selectPrevBone() -{ - const size_t oldsel = selectedBone; - do - { - selectedBone++; - if(selectedBone == oldsel) - break; - if (selectedBone >= bones.size()) - selectedBone = 0; - } - while (!bones[selectedBone]->selectable); - updateSelectedBoneColor(); -} -void SkeletalSprite::selectNextBone() -{ - const size_t oldsel = selectedBone; - do - { - selectedBone--; - if(selectedBone == oldsel) - break; - if (selectedBone >= bones.size()) - selectedBone = bones.size()-1; - } - while (!bones[selectedBone]->selectable); - updateSelectedBoneColor(); -} void BoneGridInterpolator::updateGridOnly(BoneKeyframe& bk, const Bone *bone) { diff --git a/BBGE/SkeletalSprite.h b/BBGE/SkeletalSprite.h index 2179fc4..2f7ce81 100644 --- a/BBGE/SkeletalSprite.h +++ b/BBGE/SkeletalSprite.h @@ -274,7 +274,7 @@ public: void setTimeMultiplier(float t, int layer=0); - Bone* getSelectedBone(bool mouseBased = true); + int findSelectableBoneIdxClosestTo(const Vector& pos, bool mustBeInBox = true) const; // -1 if none found, otherwise bones[idx] to get the bone Animation *getCurrentAnimation(size_t layer=0); Animation *getCurrentAnimationOrNull(size_t layer=0); @@ -284,23 +284,15 @@ public: void lastAnimation(); void firstAnimation(); bool selectAnimation(const char *name); - void updateSelectedBoneColor(); void setFreeze(bool f); - - Animation *getAnimation(const std::string& anim); std::vector animations; std::vector bones; - inline size_t getSelectedBoneIdx(void) { return selectedBone; } - void setSelectedBone(int b); - void selectPrevBone(); - void selectNextBone(); - bool isLoaded(); size_t getNumAnimLayers() const { return animLayers.size(); } @@ -319,7 +311,6 @@ protected: bool frozen; RenderObject *animKeyNotify; bool loaded; - size_t selectedBone; friend class AnimationLayer; std::vector animLayers; Bone* initBone(int idx, std::string gfx, int pidx, bool rbp=false, std::string name="", float cr=0, bool fh=false, bool fv=false);