14std::string trim(
const std::string &
s) {
16 while (
a <
s.size() && (
s[
a] ==
' ' ||
s[
a] ==
'\t' ||
s[
a] ==
'\r')) ++
a;
18 while (
b >
a && (
s[
b - 1] ==
' ' ||
s[
b - 1] ==
'\t' ||
s[
b - 1] ==
'\r')) --
b;
19 return s.substr(
a,
b -
a);
25 if (!skeleton || !
clip)
throw Exception(
"AnimImporter.exportAnimationFixtureText: null argument");
26 std::ostringstream out;
39 out <<
"clip " <<
clip->getName() <<
"\n";
40 out <<
"duration " <<
clip->getDuration() <<
"\n";
41 out <<
"loop " << (
clip->getLoop() ? 1 : 0) <<
"\n";
42 out <<
"rate " <<
clip->getSampleRate() <<
"\n";
43 for (
int i = 0; i <
clip->getSyncMarkerCount(); ++i)
44 out <<
"sync " <<
clip->getSyncMarkerTime(i) <<
" " <<
clip->getSyncMarkerName(i) <<
"\n";
46 const int np =
clip->getPositionKeyCount(
b);
47 const int nr =
clip->getRotationKeyCount(
b);
48 const int ns =
clip->getScaleKeyCount(
b);
49 if (np + nr + ns == 0)
continue;
50 out <<
"track " <<
b <<
" " << np <<
" " << nr <<
" " << ns <<
"\n";
51 for (
int i = 0; i < np; ++i) {
52 out <<
"p " <<
clip->getPositionKeyTime(
b, i) <<
" " <<
clip->getPositionKeyX(
b, i)
53 <<
" " <<
clip->getPositionKeyY(
b, i) <<
" " <<
clip->getPositionKeyZ(
b, i) <<
"\n";
55 for (
int i = 0; i < nr; ++i) {
56 out <<
"r " <<
clip->getRotationKeyTime(
b, i) <<
" " <<
clip->getRotationKeyX(
b, i)
57 <<
" " <<
clip->getRotationKeyY(
b, i) <<
" " <<
clip->getRotationKeyZ(
b, i) <<
" "
58 <<
clip->getRotationKeyW(
b, i) <<
"\n";
60 for (
int i = 0; i < ns; ++i) {
61 out <<
"s " <<
clip->getScaleKeyTime(
b, i) <<
" " <<
clip->getScaleKeyX(
b, i) <<
" "
62 <<
clip->getScaleKeyY(
b, i) <<
" " <<
clip->getScaleKeyZ(
b, i) <<
"\n";
71 if (!skeletonOut || !clipOut)
throw Exception(
"AnimImporter.importAnimationFixtureText: null out");
72 *skeletonOut =
nullptr;
79 std::istringstream in(
text);
82 while (std::getline(in,
line)) {
84 if (
line.empty() ||
line[0] ==
'#')
continue;
85 std::istringstream ls(
line);
91 if (ver != 1)
throw Exception(
"AnimImporter.importAnimationFixtureText: unsupported version");
92 }
else if (
tag ==
"skeleton") {
94 }
else if (
tag ==
"bone") {
98 std::getline(ls,
name);
100 if (
name.empty())
throw Exception(
"AnimImporter.importAnimationFixtureText: empty bone name");
101 const int id = skeleton->addBone(
name,
parent);
103 throw Exception(
"AnimImporter.importAnimationFixtureText: bone index mismatch");
105 }
else if (
tag ==
"bind") {
109 skeleton->setBindPosition(
idx,
px,
py,
pz);
112 }
else if (
tag ==
"clip") {
114 std::getline(ls,
name);
117 }
else if (
tag ==
"duration") {
118 if (!
clip)
throw Exception(
"AnimImporter.importAnimationFixtureText: duration before clip");
121 clip->setDuration(
d);
122 }
else if (
tag ==
"loop") {
123 if (!
clip)
throw Exception(
"AnimImporter.importAnimationFixtureText: loop before clip");
126 clip->setLoop(
v != 0);
127 }
else if (
tag ==
"rate") {
128 if (!
clip)
throw Exception(
"AnimImporter.importAnimationFixtureText: rate before clip");
131 clip->setSampleRate(
r);
132 }
else if (
tag ==
"sync") {
133 if (!
clip)
throw Exception(
"AnimImporter.importAnimationFixtureText: sync marker before clip");
137 std::getline(ls,
name);
140 }
else if (
tag ==
"track") {
141 if (!
clip)
throw Exception(
"AnimImporter.importAnimationFixtureText: track before clip");
142 int np = 0, nr = 0, ns = 0;
143 ls >> curBone >> np >> nr >> ns;
147 }
else if (
tag ==
"p") {
149 ls >>
t >>
x >>
y >>
z;
150 clip->addPositionKey(curBone,
t,
x,
y,
z);
151 }
else if (
tag ==
"r") {
153 ls >>
t >>
x >>
y >>
z >>
w;
154 clip->addRotationKey(curBone,
t,
x,
y,
z,
w);
155 }
else if (
tag ==
"s") {
157 ls >>
t >>
x >>
y >>
z;
158 clip->addScaleKey(curBone,
t,
x,
y,
z);
159 }
else if (
tag ==
"end") {
163 if (!
clip)
throw Exception(
"AnimImporter.importAnimationFixtureText: missing clip");
164 *skeletonOut = skeleton;
175 std::ifstream in(
path);
176 if (!in)
throw Exception(
"AnimImporter.importAnimationFixtureTextFile: cannot open %s",
path.c_str());
177 std::ostringstream ss;
EVENGINE_API_FOUNDATION public API.
Keyframed skeletal animation clip (local TRS tracks per bone). Script type: AnimClip.
static std::string exportAnimationFixtureText(const AnimSkeleton *skeleton, const AnimClip *clip)
Serialize skeleton + clip to a compact text format (no mesh). Used to ship Mixamo-derived test fixtur...
static void importAnimationFixtureTextFile(const std::string &path, AnimSkeleton **skeletonOut, AnimClip **clipOut)
Load from an *.anim.txt fixture path.
static void importAnimationFixtureText(const std::string &text, AnimSkeleton **skeletonOut, AnimClip **clipOut)
Load skeleton+clip from fixture text (new'd; caller owns).
3D bone hierarchy + bind-pose local TRS for skeletal animation. Independent of ik::Skeleton3D (FABRIK...
float getBindPositionY(int boneIndex) const
Returns the bind position y.
float getBindScaleX(int boneIndex) const
Returns the bind scale x.
int getBoneCount() const
Returns the bone count.
int getParent(int boneIndex) const
Returns the parent.
float getBindPositionZ(int boneIndex) const
Returns the bind position z.
float getBindRotationW(int boneIndex) const
Returns the bind rotation w.
float getBindScaleY(int boneIndex) const
Returns the bind scale y.
float getBindRotationY(int boneIndex) const
Returns the bind rotation y.
float getBindScaleZ(int boneIndex) const
Returns the bind scale z.
float getBindPositionX(int boneIndex) const
Returns the bind position x.
float getBindRotationZ(int boneIndex) const
Returns the bind rotation z.
float getBindRotationX(int boneIndex) const
Returns the bind rotation x.
std::string getBoneName(int boneIndex) const
Returns the bone name.