-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBoneDragRelease.cpp
More file actions
77 lines (68 loc) · 3.14 KB
/
BoneDragRelease.cpp
File metadata and controls
77 lines (68 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include "BoneDragRelease.h"
#include <OgreBone.h>
#include <OgreEntity.h>
#include <cmath>
namespace {
// Drag accumulates float noise via projection / parent-frame conversions;
// 1e-5 keeps us well below user-perceivable motion while filtering bit-
// level drift that would otherwise produce stray Commit/CommitBind on
// press/release with no real motion.
constexpr float kPosEpsilon = 1e-5f;
constexpr float kScaleEpsilon = 1e-5f;
constexpr float kQuatDotEps = 1e-6f;
bool nearlyEqual(const Ogre::Vector3& a, const Ogre::Vector3& b, float eps) {
return (a - b).squaredLength() <= eps * eps;
}
bool nearlyEqual(const Ogre::Quaternion& a, const Ogre::Quaternion& b, float eps) {
// 1 - |dot| ≈ 0 when quats represent the same rotation (handles
// sign flip with the absolute value).
return (1.0f - std::fabs(a.Dot(b))) <= eps;
}
}
BoneDragRelease::Result BoneDragRelease::apply(Ogre::Bone* bone,
const Ogre::Vector3& beforePos,
const Ogre::Quaternion& beforeOrient,
const Ogre::Vector3& beforeScale,
bool hasActiveAnim,
bool autoKeyOn,
Ogre::Entity* entityForUpdate)
{
if (!bone) return Result::NoOp;
// Tolerant comparison — drag math can accumulate sub-microsecond
// float noise that would otherwise mis-fire Commit on a press/
// release with no intended motion.
const bool changed = !nearlyEqual(bone->getPosition(), beforePos, kPosEpsilon)
|| !nearlyEqual(bone->getOrientation(), beforeOrient, kQuatDotEps)
|| !nearlyEqual(bone->getScale(), beforeScale, kScaleEpsilon);
if (!changed) {
// Even "no change" should release manual control if it was set
// during the (zero-delta) drag.
bone->setManuallyControlled(false);
return Result::NoOp;
}
if (autoKeyOn && hasActiveAnim) {
// Caller writes the keyframe (via AnimationControlController) and
// pushes BoneTransformCommand. We just unfreeze the bone so the
// curve drives playback through the new key.
bone->setManuallyControlled(false);
return Result::Commit;
}
if (hasActiveAnim) {
// Preview only: revert bone to its pre-drag local TRS so playback
// is unaffected. Don't call setInitialState — the curve stores
// deltas relative to initial; changing initial would double-apply
// the curve delta on next sample.
bone->setPosition(beforePos);
bone->setOrientation(beforeOrient);
bone->setScale(beforeScale);
bone->setManuallyControlled(false);
bone->needUpdate(true);
if (entityForUpdate) entityForUpdate->_updateAnimation();
return Result::Revert;
}
// No active animation: T-pose / bind-pose authoring. The dragged
// local TRS becomes the new bind pose.
bone->setInitialState();
bone->setManuallyControlled(false);
return Result::CommitBind;
}