Merge branch 'master' of https://github.com/assimp/assimp
commit
8d3853022a
|
@ -1971,6 +1971,9 @@ private:
|
||||||
if (name.substr(0, 16) == "AnimationStack::") {
|
if (name.substr(0, 16) == "AnimationStack::") {
|
||||||
name = name.substr(16);
|
name = name.substr(16);
|
||||||
}
|
}
|
||||||
|
else if (name.substr(0, 11) == "AnimStack::") {
|
||||||
|
name = name.substr(11);
|
||||||
|
}
|
||||||
|
|
||||||
anim->mName.Set(name);
|
anim->mName.Set(name);
|
||||||
|
|
||||||
|
@ -2014,12 +2017,18 @@ private:
|
||||||
double min_time = 1e10;
|
double min_time = 1e10;
|
||||||
double max_time = -1e10;
|
double max_time = -1e10;
|
||||||
|
|
||||||
|
int64_t start_time = st.LocalStart();
|
||||||
|
int64_t stop_time = st.LocalStop();
|
||||||
|
double start_timeF = CONVERT_FBX_TIME(start_time);
|
||||||
|
double stop_timeF = CONVERT_FBX_TIME(stop_time);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BOOST_FOREACH(const NodeMap::value_type& kv, node_map) {
|
BOOST_FOREACH(const NodeMap::value_type& kv, node_map) {
|
||||||
GenerateNodeAnimations(node_anims,
|
GenerateNodeAnimations(node_anims,
|
||||||
kv.first,
|
kv.first,
|
||||||
kv.second,
|
kv.second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start_time, stop_time,
|
||||||
max_time,
|
max_time,
|
||||||
min_time);
|
min_time);
|
||||||
}
|
}
|
||||||
|
@ -2043,9 +2052,27 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//adjust relative timing for animation
|
||||||
|
{
|
||||||
|
double start_fps = start_timeF * anim_fps;
|
||||||
|
|
||||||
|
for (unsigned int c = 0; c < anim->mNumChannels; c++)
|
||||||
|
{
|
||||||
|
aiNodeAnim* channel = anim->mChannels[c];
|
||||||
|
for (uint32_t i = 0; i < channel->mNumPositionKeys; i++)
|
||||||
|
channel->mPositionKeys[i].mTime -= start_fps;
|
||||||
|
for (uint32_t i = 0; i < channel->mNumRotationKeys; i++)
|
||||||
|
channel->mRotationKeys[i].mTime -= start_fps;
|
||||||
|
for (uint32_t i = 0; i < channel->mNumScalingKeys; i++)
|
||||||
|
channel->mScalingKeys[i].mTime -= start_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_time -= min_time;
|
||||||
|
}
|
||||||
|
|
||||||
// for some mysterious reason, mDuration is simply the maximum key -- the
|
// for some mysterious reason, mDuration is simply the maximum key -- the
|
||||||
// validator always assumes animations to start at zero.
|
// validator always assumes animations to start at zero.
|
||||||
anim->mDuration = max_time /*- min_time */;
|
anim->mDuration = (stop_timeF - start_timeF) * anim_fps;
|
||||||
anim->mTicksPerSecond = anim_fps;
|
anim->mTicksPerSecond = anim_fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2055,6 +2082,7 @@ private:
|
||||||
const std::string& fixed_name,
|
const std::string& fixed_name,
|
||||||
const std::vector<const AnimationCurveNode*>& curves,
|
const std::vector<const AnimationCurveNode*>& curves,
|
||||||
const LayerMap& layer_map,
|
const LayerMap& layer_map,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& max_time,
|
double& max_time,
|
||||||
double& min_time)
|
double& min_time)
|
||||||
{
|
{
|
||||||
|
@ -2147,13 +2175,19 @@ private:
|
||||||
aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
|
aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
|
||||||
node_property_map.end(),
|
node_property_map.end(),
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time,
|
min_time,
|
||||||
true // input is TRS order, assimp is SRT
|
true // input is TRS order, assimp is SRT
|
||||||
);
|
);
|
||||||
|
|
||||||
ai_assert(nd);
|
ai_assert(nd);
|
||||||
|
if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) {
|
||||||
|
delete nd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
node_anims.push_back(nd);
|
node_anims.push_back(nd);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2185,6 +2219,7 @@ private:
|
||||||
target,
|
target,
|
||||||
(*chain[i]).second,
|
(*chain[i]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time);
|
min_time);
|
||||||
|
|
||||||
|
@ -2200,6 +2235,7 @@ private:
|
||||||
target,
|
target,
|
||||||
(*chain[i]).second,
|
(*chain[i]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time);
|
min_time);
|
||||||
|
|
||||||
|
@ -2212,12 +2248,18 @@ private:
|
||||||
target,
|
target,
|
||||||
(*chain[i]).second,
|
(*chain[i]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time,
|
min_time,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
ai_assert(inv);
|
ai_assert(inv);
|
||||||
|
if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) {
|
||||||
|
delete inv;
|
||||||
|
}
|
||||||
|
else {
|
||||||
node_anims.push_back(inv);
|
node_anims.push_back(inv);
|
||||||
|
}
|
||||||
|
|
||||||
ai_assert(TransformationComp_RotationPivotInverse > i);
|
ai_assert(TransformationComp_RotationPivotInverse > i);
|
||||||
flags |= bit << (TransformationComp_RotationPivotInverse - i);
|
flags |= bit << (TransformationComp_RotationPivotInverse - i);
|
||||||
|
@ -2230,12 +2272,18 @@ private:
|
||||||
target,
|
target,
|
||||||
(*chain[i]).second,
|
(*chain[i]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time,
|
min_time,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
ai_assert(inv);
|
ai_assert(inv);
|
||||||
|
if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) {
|
||||||
|
delete inv;
|
||||||
|
}
|
||||||
|
else {
|
||||||
node_anims.push_back(inv);
|
node_anims.push_back(inv);
|
||||||
|
}
|
||||||
|
|
||||||
ai_assert(TransformationComp_RotationPivotInverse > i);
|
ai_assert(TransformationComp_RotationPivotInverse > i);
|
||||||
flags |= bit << (TransformationComp_RotationPivotInverse - i);
|
flags |= bit << (TransformationComp_RotationPivotInverse - i);
|
||||||
|
@ -2249,6 +2297,7 @@ private:
|
||||||
target,
|
target,
|
||||||
(*chain[i]).second,
|
(*chain[i]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time);
|
min_time);
|
||||||
|
|
||||||
|
@ -2259,7 +2308,12 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
ai_assert(na);
|
ai_assert(na);
|
||||||
|
if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) {
|
||||||
|
delete na;
|
||||||
|
}
|
||||||
|
else {
|
||||||
node_anims.push_back(na);
|
node_anims.push_back(na);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2320,13 +2374,14 @@ private:
|
||||||
const Model& target,
|
const Model& target,
|
||||||
const std::vector<const AnimationCurveNode*>& curves,
|
const std::vector<const AnimationCurveNode*>& curves,
|
||||||
const LayerMap& layer_map,
|
const LayerMap& layer_map,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& max_time,
|
double& max_time,
|
||||||
double& min_time)
|
double& min_time)
|
||||||
{
|
{
|
||||||
ScopeGuard<aiNodeAnim> na(new aiNodeAnim());
|
ScopeGuard<aiNodeAnim> na(new aiNodeAnim());
|
||||||
na->mNodeName.Set(name);
|
na->mNodeName.Set(name);
|
||||||
|
|
||||||
ConvertRotationKeys(na, curves, layer_map, max_time,min_time, target.RotationOrder());
|
ConvertRotationKeys(na, curves, layer_map, start, stop, max_time, min_time, target.RotationOrder());
|
||||||
|
|
||||||
// dummy scaling key
|
// dummy scaling key
|
||||||
na->mScalingKeys = new aiVectorKey[1];
|
na->mScalingKeys = new aiVectorKey[1];
|
||||||
|
@ -2351,13 +2406,14 @@ private:
|
||||||
const Model& /*target*/,
|
const Model& /*target*/,
|
||||||
const std::vector<const AnimationCurveNode*>& curves,
|
const std::vector<const AnimationCurveNode*>& curves,
|
||||||
const LayerMap& layer_map,
|
const LayerMap& layer_map,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& max_time,
|
double& max_time,
|
||||||
double& min_time)
|
double& min_time)
|
||||||
{
|
{
|
||||||
ScopeGuard<aiNodeAnim> na(new aiNodeAnim());
|
ScopeGuard<aiNodeAnim> na(new aiNodeAnim());
|
||||||
na->mNodeName.Set(name);
|
na->mNodeName.Set(name);
|
||||||
|
|
||||||
ConvertScaleKeys(na, curves, layer_map, max_time,min_time);
|
ConvertScaleKeys(na, curves, layer_map, start, stop, max_time, min_time);
|
||||||
|
|
||||||
// dummy rotation key
|
// dummy rotation key
|
||||||
na->mRotationKeys = new aiQuatKey[1];
|
na->mRotationKeys = new aiQuatKey[1];
|
||||||
|
@ -2382,6 +2438,7 @@ private:
|
||||||
const Model& /*target*/,
|
const Model& /*target*/,
|
||||||
const std::vector<const AnimationCurveNode*>& curves,
|
const std::vector<const AnimationCurveNode*>& curves,
|
||||||
const LayerMap& layer_map,
|
const LayerMap& layer_map,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& max_time,
|
double& max_time,
|
||||||
double& min_time,
|
double& min_time,
|
||||||
bool inverse = false)
|
bool inverse = false)
|
||||||
|
@ -2389,7 +2446,7 @@ private:
|
||||||
ScopeGuard<aiNodeAnim> na(new aiNodeAnim());
|
ScopeGuard<aiNodeAnim> na(new aiNodeAnim());
|
||||||
na->mNodeName.Set(name);
|
na->mNodeName.Set(name);
|
||||||
|
|
||||||
ConvertTranslationKeys(na, curves, layer_map, max_time,min_time);
|
ConvertTranslationKeys(na, curves, layer_map, start, stop, max_time, min_time);
|
||||||
|
|
||||||
if (inverse) {
|
if (inverse) {
|
||||||
for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) {
|
for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) {
|
||||||
|
@ -2422,6 +2479,7 @@ private:
|
||||||
NodeMap::const_iterator chain[TransformationComp_MAXIMUM],
|
NodeMap::const_iterator chain[TransformationComp_MAXIMUM],
|
||||||
NodeMap::const_iterator iter_end,
|
NodeMap::const_iterator iter_end,
|
||||||
const LayerMap& layer_map,
|
const LayerMap& layer_map,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& max_time,
|
double& max_time,
|
||||||
double& min_time,
|
double& min_time,
|
||||||
bool reverse_order = false)
|
bool reverse_order = false)
|
||||||
|
@ -2443,21 +2501,21 @@ private:
|
||||||
KeyFrameListList rotation;
|
KeyFrameListList rotation;
|
||||||
|
|
||||||
if(chain[TransformationComp_Scaling] != iter_end) {
|
if(chain[TransformationComp_Scaling] != iter_end) {
|
||||||
scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second);
|
scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f));
|
def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chain[TransformationComp_Translation] != iter_end) {
|
if(chain[TransformationComp_Translation] != iter_end) {
|
||||||
translation = GetKeyframeList((*chain[TransformationComp_Translation]).second);
|
translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f));
|
def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chain[TransformationComp_Rotation] != iter_end) {
|
if(chain[TransformationComp_Rotation] != iter_end) {
|
||||||
rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second);
|
rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
def_rot = EulerToQuaternion(PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f)),
|
def_rot = EulerToQuaternion(PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f)),
|
||||||
|
@ -2475,6 +2533,8 @@ private:
|
||||||
aiVectorKey* out_scale = new aiVectorKey[times.size()];
|
aiVectorKey* out_scale = new aiVectorKey[times.size()];
|
||||||
aiVectorKey* out_translation = new aiVectorKey[times.size()];
|
aiVectorKey* out_translation = new aiVectorKey[times.size()];
|
||||||
|
|
||||||
|
if (times.size())
|
||||||
|
{
|
||||||
ConvertTransformOrder_TRStoSRT(out_quat, out_scale, out_translation,
|
ConvertTransformOrder_TRStoSRT(out_quat, out_scale, out_translation,
|
||||||
scaling,
|
scaling,
|
||||||
translation,
|
translation,
|
||||||
|
@ -2486,6 +2546,7 @@ private:
|
||||||
def_scale,
|
def_scale,
|
||||||
def_translate,
|
def_translate,
|
||||||
def_rot);
|
def_rot);
|
||||||
|
}
|
||||||
|
|
||||||
// XXX remove duplicates / redundant keys which this operation did
|
// XXX remove duplicates / redundant keys which this operation did
|
||||||
// likely produce if not all three channels were equally dense.
|
// likely produce if not all three channels were equally dense.
|
||||||
|
@ -2507,6 +2568,7 @@ private:
|
||||||
if(chain[TransformationComp_Scaling] != iter_end) {
|
if(chain[TransformationComp_Scaling] != iter_end) {
|
||||||
ConvertScaleKeys(na, (*chain[TransformationComp_Scaling]).second,
|
ConvertScaleKeys(na, (*chain[TransformationComp_Scaling]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time);
|
min_time);
|
||||||
}
|
}
|
||||||
|
@ -2522,6 +2584,7 @@ private:
|
||||||
if(chain[TransformationComp_Rotation] != iter_end) {
|
if(chain[TransformationComp_Rotation] != iter_end) {
|
||||||
ConvertRotationKeys(na, (*chain[TransformationComp_Rotation]).second,
|
ConvertRotationKeys(na, (*chain[TransformationComp_Rotation]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time,
|
min_time,
|
||||||
target.RotationOrder());
|
target.RotationOrder());
|
||||||
|
@ -2539,6 +2602,7 @@ private:
|
||||||
if(chain[TransformationComp_Translation] != iter_end) {
|
if(chain[TransformationComp_Translation] != iter_end) {
|
||||||
ConvertTranslationKeys(na, (*chain[TransformationComp_Translation]).second,
|
ConvertTranslationKeys(na, (*chain[TransformationComp_Translation]).second,
|
||||||
layer_map,
|
layer_map,
|
||||||
|
start, stop,
|
||||||
max_time,
|
max_time,
|
||||||
min_time);
|
min_time);
|
||||||
}
|
}
|
||||||
|
@ -2558,17 +2622,21 @@ private:
|
||||||
|
|
||||||
|
|
||||||
// key (time), value, mapto (component index)
|
// key (time), value, mapto (component index)
|
||||||
typedef boost::tuple< const KeyTimeList*, const KeyValueList*, unsigned int > KeyFrameList;
|
typedef boost::tuple<boost::shared_ptr<KeyTimeList>, boost::shared_ptr<KeyValueList>, unsigned int > KeyFrameList;
|
||||||
typedef std::vector<KeyFrameList> KeyFrameListList;
|
typedef std::vector<KeyFrameList> KeyFrameListList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes)
|
KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop)
|
||||||
{
|
{
|
||||||
KeyFrameListList inputs;
|
KeyFrameListList inputs;
|
||||||
inputs.reserve(nodes.size()*3);
|
inputs.reserve(nodes.size()*3);
|
||||||
|
|
||||||
|
//give some breathing room for rounding errors
|
||||||
|
int64_t adj_start = start - 10000;
|
||||||
|
int64_t adj_stop = stop + 10000;
|
||||||
|
|
||||||
BOOST_FOREACH(const AnimationCurveNode* node, nodes) {
|
BOOST_FOREACH(const AnimationCurveNode* node, nodes) {
|
||||||
ai_assert(node);
|
ai_assert(node);
|
||||||
|
|
||||||
|
@ -2593,7 +2661,23 @@ private:
|
||||||
const AnimationCurve* const curve = kv.second;
|
const AnimationCurve* const curve = kv.second;
|
||||||
ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size());
|
ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size());
|
||||||
|
|
||||||
inputs.push_back(boost::make_tuple(&curve->GetKeys(), &curve->GetValues(), mapto));
|
//get values within the start/stop time window
|
||||||
|
boost::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
|
||||||
|
boost::shared_ptr<KeyValueList> Values(new KeyValueList());
|
||||||
|
const int count = curve->GetKeys().size();
|
||||||
|
Keys->reserve(count);
|
||||||
|
Values->reserve(count);
|
||||||
|
for (int n = 0; n < count; n++)
|
||||||
|
{
|
||||||
|
int64_t k = curve->GetKeys().at(n);
|
||||||
|
if (k >= adj_start && k <= adj_stop)
|
||||||
|
{
|
||||||
|
Keys->push_back(k);
|
||||||
|
Values->push_back(curve->GetValues().at(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.push_back(boost::make_tuple(Keys, Values, mapto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return inputs; // pray for NRVO :-)
|
return inputs; // pray for NRVO :-)
|
||||||
|
@ -2623,7 +2707,7 @@ private:
|
||||||
const size_t count = inputs.size();
|
const size_t count = inputs.size();
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
||||||
uint64_t min_tick = std::numeric_limits<uint64_t>::max();
|
int64_t min_tick = std::numeric_limits<int64_t>::max();
|
||||||
for (size_t i = 0; i < count; ++i) {
|
for (size_t i = 0; i < count; ++i) {
|
||||||
const KeyFrameList& kfl = inputs[i];
|
const KeyFrameList& kfl = inputs[i];
|
||||||
|
|
||||||
|
@ -2632,7 +2716,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min_tick == std::numeric_limits<uint64_t>::max()) {
|
if (min_tick == std::numeric_limits<int64_t>::max()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
keys.push_back(min_tick);
|
keys.push_back(min_tick);
|
||||||
|
@ -2832,6 +2916,7 @@ private:
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
|
void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& maxTime,
|
double& maxTime,
|
||||||
double& minTime)
|
double& minTime)
|
||||||
{
|
{
|
||||||
|
@ -2841,11 +2926,12 @@ private:
|
||||||
// layers should be multiplied with each other). There is a FBX
|
// layers should be multiplied with each other). There is a FBX
|
||||||
// property in the layer to specify the behaviour, though.
|
// property in the layer to specify the behaviour, though.
|
||||||
|
|
||||||
const KeyFrameListList& inputs = GetKeyframeList(nodes);
|
const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop);
|
||||||
const KeyTimeList& keys = GetKeyTimeList(inputs);
|
const KeyTimeList& keys = GetKeyTimeList(inputs);
|
||||||
|
|
||||||
na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
|
na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
|
||||||
na->mScalingKeys = new aiVectorKey[keys.size()];
|
na->mScalingKeys = new aiVectorKey[keys.size()];
|
||||||
|
if (keys.size() > 0)
|
||||||
InterpolateKeys(na->mScalingKeys, keys, inputs, true, maxTime, minTime);
|
InterpolateKeys(na->mScalingKeys, keys, inputs, true, maxTime, minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2853,17 +2939,19 @@ private:
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
|
void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
|
||||||
const LayerMap& /*layers*/,
|
const LayerMap& /*layers*/,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& maxTime,
|
double& maxTime,
|
||||||
double& minTime)
|
double& minTime)
|
||||||
{
|
{
|
||||||
ai_assert(nodes.size());
|
ai_assert(nodes.size());
|
||||||
|
|
||||||
// XXX see notes in ConvertScaleKeys()
|
// XXX see notes in ConvertScaleKeys()
|
||||||
const KeyFrameListList& inputs = GetKeyframeList(nodes);
|
const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop);
|
||||||
const KeyTimeList& keys = GetKeyTimeList(inputs);
|
const KeyTimeList& keys = GetKeyTimeList(inputs);
|
||||||
|
|
||||||
na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
|
na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
|
||||||
na->mPositionKeys = new aiVectorKey[keys.size()];
|
na->mPositionKeys = new aiVectorKey[keys.size()];
|
||||||
|
if (keys.size() > 0)
|
||||||
InterpolateKeys(na->mPositionKeys, keys, inputs, false, maxTime, minTime);
|
InterpolateKeys(na->mPositionKeys, keys, inputs, false, maxTime, minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2871,6 +2959,7 @@ private:
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
|
void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
|
||||||
const LayerMap& /*layers*/,
|
const LayerMap& /*layers*/,
|
||||||
|
int64_t start, int64_t stop,
|
||||||
double& maxTime,
|
double& maxTime,
|
||||||
double& minTime,
|
double& minTime,
|
||||||
Model::RotOrder order)
|
Model::RotOrder order)
|
||||||
|
@ -2878,11 +2967,12 @@ private:
|
||||||
ai_assert(nodes.size());
|
ai_assert(nodes.size());
|
||||||
|
|
||||||
// XXX see notes in ConvertScaleKeys()
|
// XXX see notes in ConvertScaleKeys()
|
||||||
const std::vector< KeyFrameList >& inputs = GetKeyframeList(nodes);
|
const std::vector< KeyFrameList >& inputs = GetKeyframeList(nodes, start, stop);
|
||||||
const KeyTimeList& keys = GetKeyTimeList(inputs);
|
const KeyTimeList& keys = GetKeyTimeList(inputs);
|
||||||
|
|
||||||
na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
|
na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
|
||||||
na->mRotationKeys = new aiQuatKey[keys.size()];
|
na->mRotationKeys = new aiQuatKey[keys.size()];
|
||||||
|
if (keys.size() > 0)
|
||||||
InterpolateKeys(na->mRotationKeys, keys, inputs, false, maxTime, minTime, order);
|
InterpolateKeys(na->mRotationKeys, keys, inputs, false, maxTime, minTime, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -871,7 +871,7 @@ private:
|
||||||
std::vector<unsigned int> mappings;
|
std::vector<unsigned int> mappings;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<uint64_t> KeyTimeList;
|
typedef std::vector<int64_t> KeyTimeList;
|
||||||
typedef std::vector<float> KeyValueList;
|
typedef std::vector<float> KeyValueList;
|
||||||
|
|
||||||
/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */
|
/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */
|
||||||
|
@ -1015,10 +1015,10 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
fbx_simple_property(LocalStart, uint64_t, 0L)
|
fbx_simple_property(LocalStart, int64_t, 0L)
|
||||||
fbx_simple_property(LocalStop, uint64_t, 0L)
|
fbx_simple_property(LocalStop, int64_t, 0L)
|
||||||
fbx_simple_property(ReferenceStart, uint64_t, 0L)
|
fbx_simple_property(ReferenceStart, int64_t, 0L)
|
||||||
fbx_simple_property(ReferenceStop, uint64_t, 0L)
|
fbx_simple_property(ReferenceStop, int64_t, 0L)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -431,6 +431,43 @@ int ParseTokenAsInt(const Token& t, const char*& err_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
|
||||||
|
{
|
||||||
|
err_out = NULL;
|
||||||
|
|
||||||
|
if (t.Type() != TokenType_DATA) {
|
||||||
|
err_out = "expected TOK_DATA token";
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.IsBinary())
|
||||||
|
{
|
||||||
|
const char* data = t.begin();
|
||||||
|
if (data[0] != 'L') {
|
||||||
|
err_out = "failed to parse Int64, unexpected data type";
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end());
|
||||||
|
AI_SWAP8(id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: should use size_t here
|
||||||
|
unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
|
||||||
|
ai_assert(length > 0);
|
||||||
|
|
||||||
|
const char* out;
|
||||||
|
const int64_t id = strtoul10_64(t.begin(), &out, &length);
|
||||||
|
if (out > t.end()) {
|
||||||
|
err_out = "failed to parse Int64 (text)";
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string ParseTokenAsString(const Token& t, const char*& err_out)
|
std::string ParseTokenAsString(const Token& t, const char*& err_out)
|
||||||
{
|
{
|
||||||
|
@ -1062,6 +1099,63 @@ void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of int64_ts
|
||||||
|
void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
if (tok.empty()) {
|
||||||
|
ParseError("unexpected empty element", &el);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok[0]->IsBinary()) {
|
||||||
|
const char* data = tok[0]->begin(), *end = tok[0]->end();
|
||||||
|
|
||||||
|
char type;
|
||||||
|
uint32_t count;
|
||||||
|
ReadBinaryDataArrayHead(data, end, type, count, el);
|
||||||
|
|
||||||
|
if (!count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != 'l') {
|
||||||
|
ParseError("expected long array (binary)", &el);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> buff;
|
||||||
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
|
ai_assert(data == end);
|
||||||
|
ai_assert(buff.size() == count * 8);
|
||||||
|
|
||||||
|
out.reserve(count);
|
||||||
|
|
||||||
|
const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]);
|
||||||
|
for (unsigned int i = 0; i < count; ++i, ++ip) {
|
||||||
|
BE_NCONST int64_t val = *ip;
|
||||||
|
AI_SWAP8(val);
|
||||||
|
out.push_back(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray()
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope, "a", &el);
|
||||||
|
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) {
|
||||||
|
const int64_t ival = ParseTokenAsInt64(**it++);
|
||||||
|
|
||||||
|
out.push_back(ival);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
aiMatrix4x4 ReadMatrix(const Element& element)
|
aiMatrix4x4 ReadMatrix(const Element& element)
|
||||||
|
@ -1205,6 +1299,18 @@ int ParseTokenAsInt(const Token& t)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// wrapper around ParseTokenAsInt64() with ParseError handling
|
||||||
|
int64_t ParseTokenAsInt64(const Token& t)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
const int64_t i = ParseTokenAsInt64(t, err);
|
||||||
|
if (err) {
|
||||||
|
ParseError(err, t);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
} // !FBX
|
} // !FBX
|
||||||
} // !Assimp
|
} // !Assimp
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,7 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out);
|
||||||
|
|
||||||
float ParseTokenAsFloat(const Token& t, const char*& err_out);
|
float ParseTokenAsFloat(const Token& t, const char*& err_out);
|
||||||
int ParseTokenAsInt(const Token& t, const char*& err_out);
|
int ParseTokenAsInt(const Token& t, const char*& err_out);
|
||||||
|
int64_t ParseTokenAsInt64(const Token& t, const char*& err_out);
|
||||||
std::string ParseTokenAsString(const Token& t, const char*& err_out);
|
std::string ParseTokenAsString(const Token& t, const char*& err_out);
|
||||||
|
|
||||||
|
|
||||||
|
@ -214,6 +215,7 @@ uint64_t ParseTokenAsID(const Token& t);
|
||||||
size_t ParseTokenAsDim(const Token& t);
|
size_t ParseTokenAsDim(const Token& t);
|
||||||
float ParseTokenAsFloat(const Token& t);
|
float ParseTokenAsFloat(const Token& t);
|
||||||
int ParseTokenAsInt(const Token& t);
|
int ParseTokenAsInt(const Token& t);
|
||||||
|
int64_t ParseTokenAsInt64(const Token& t);
|
||||||
std::string ParseTokenAsString(const Token& t);
|
std::string ParseTokenAsString(const Token& t);
|
||||||
|
|
||||||
/* read data arrays */
|
/* read data arrays */
|
||||||
|
@ -224,6 +226,7 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el);
|
||||||
void ParseVectorDataArray(std::vector<float>& out, const Element& el);
|
void ParseVectorDataArray(std::vector<float>& out, const Element& el);
|
||||||
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
|
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
|
||||||
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
|
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
|
||||||
|
void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,9 @@ Property* ReadTypedProperty(const Element& element)
|
||||||
else if (!strcmp(cs, "ULongLong")) {
|
else if (!strcmp(cs, "ULongLong")) {
|
||||||
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
|
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(cs, "KTime")) {
|
||||||
|
return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
|
||||||
|
}
|
||||||
else if (!strcmp(cs,"Vector3D") ||
|
else if (!strcmp(cs,"Vector3D") ||
|
||||||
!strcmp(cs,"ColorRGB") ||
|
!strcmp(cs,"ColorRGB") ||
|
||||||
!strcmp(cs,"Vector") ||
|
!strcmp(cs,"Vector") ||
|
||||||
|
@ -105,7 +108,7 @@ Property* ReadTypedProperty(const Element& element)
|
||||||
ParseTokenAsFloat(*tok[6]))
|
ParseTokenAsFloat(*tok[6]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"KTime") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
|
else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
|
||||||
return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
|
return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -856,6 +856,14 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataArrayList *createDataArrayList( Value *currentValue, size_t numValues ) {
|
||||||
|
DataArrayList *dataList = new DataArrayList;
|
||||||
|
dataList->m_dataList = currentValue;
|
||||||
|
dataList->m_numItems = numValues;
|
||||||
|
|
||||||
|
return dataList;
|
||||||
|
|
||||||
|
}
|
||||||
char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **dataList ) {
|
char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **dataList ) {
|
||||||
*dataList = ddl_nullptr;
|
*dataList = ddl_nullptr;
|
||||||
if( ddl_nullptr == in || in == end ) {
|
if( ddl_nullptr == in || in == end ) {
|
||||||
|
@ -865,20 +873,19 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **da
|
||||||
in = lookForNextToken( in, end );
|
in = lookForNextToken( in, end );
|
||||||
if( *in == Grammar::OpenBracketToken[ 0 ] ) {
|
if( *in == Grammar::OpenBracketToken[ 0 ] ) {
|
||||||
in++;
|
in++;
|
||||||
Value *current( ddl_nullptr );
|
Value *currentValue( ddl_nullptr );
|
||||||
Reference *refs( ddl_nullptr );
|
Reference *refs( ddl_nullptr );
|
||||||
DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr );
|
DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr );
|
||||||
do {
|
do {
|
||||||
size_t numRefs( 0 ), numValues( 0 );
|
size_t numRefs( 0 ), numValues( 0 );
|
||||||
in = parseDataList( in, end, ¤t, numValues, &refs, numRefs );
|
currentValue = ddl_nullptr;
|
||||||
if( ddl_nullptr != current ) {
|
in = parseDataList( in, end, ¤tValue, numValues, &refs, numRefs );
|
||||||
|
if( ddl_nullptr != currentValue ) {
|
||||||
if( ddl_nullptr == prev ) {
|
if( ddl_nullptr == prev ) {
|
||||||
*dataList = new DataArrayList;
|
*dataList = createDataArrayList( currentValue, numValues );
|
||||||
( *dataList )->m_dataList = current;
|
|
||||||
( *dataList )->m_numItems = numValues;
|
|
||||||
prev = *dataList;
|
prev = *dataList;
|
||||||
} else {
|
} else {
|
||||||
currentDataList = new DataArrayList;
|
currentDataList = createDataArrayList( currentValue, numValues );
|
||||||
if( ddl_nullptr != prev ) {
|
if( ddl_nullptr != prev ) {
|
||||||
prev->m_next = currentDataList;
|
prev->m_next = currentDataList;
|
||||||
prev = currentDataList;
|
prev = currentDataList;
|
||||||
|
|
|
@ -1340,6 +1340,14 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize
|
||||||
|
(JNIEnv *env, jclass jClazz)
|
||||||
|
{
|
||||||
|
const int res = sizeof(aiVectorKey);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
|
JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
|
||||||
(JNIEnv *env, jclass jClazz)
|
(JNIEnv *env, jclass jClazz)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize
|
||||||
|
(JNIEnv *, jclass);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: jassimp_Jassimp
|
* Class: jassimp_Jassimp
|
||||||
* Method: getErrorString
|
* Method: getErrorString
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Open Asset Import Library - Java Binding (jassimp)
|
Open Asset Import Library - Java Binding (jassimp)
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2012, assimp team
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -68,9 +68,9 @@ import java.nio.ByteOrder;
|
||||||
*/
|
*/
|
||||||
public final class AiNodeAnim {
|
public final class AiNodeAnim {
|
||||||
/**
|
/**
|
||||||
* Size of one position key entry (includes padding).
|
* Size of one position key entry.
|
||||||
*/
|
*/
|
||||||
private static final int POS_KEY_SIZE = 24;
|
private static final int POS_KEY_SIZE = Jassimp.getVKeysize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of one rotation key entry.
|
* Size of one rotation key entry.
|
||||||
|
@ -78,9 +78,9 @@ public final class AiNodeAnim {
|
||||||
private static final int ROT_KEY_SIZE = 24;
|
private static final int ROT_KEY_SIZE = 24;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of one scaling key entry (includes padding).
|
* Size of one scaling key entry.
|
||||||
*/
|
*/
|
||||||
private static final int SCALE_KEY_SIZE = 24;
|
private static final int SCALE_KEY_SIZE = Jassimp.getVKeysize();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,14 +103,13 @@ public final class AiNodeAnim {
|
||||||
m_preState = AiAnimBehavior.fromRawValue(preBehavior);
|
m_preState = AiAnimBehavior.fromRawValue(preBehavior);
|
||||||
m_postState = AiAnimBehavior.fromRawValue(postBehavior);
|
m_postState = AiAnimBehavior.fromRawValue(postBehavior);
|
||||||
|
|
||||||
/* c data is padded -> 24 bytes with 20 bytes data */
|
|
||||||
m_posKeys = ByteBuffer.allocateDirect(numPosKeys * POS_KEY_SIZE);
|
m_posKeys = ByteBuffer.allocateDirect(numPosKeys * POS_KEY_SIZE);
|
||||||
m_posKeys.order(ByteOrder.nativeOrder());
|
m_posKeys.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
m_rotKeys = ByteBuffer.allocateDirect(numRotKeys * 24);
|
m_rotKeys = ByteBuffer.allocateDirect(numRotKeys * ROT_KEY_SIZE);
|
||||||
m_rotKeys.order(ByteOrder.nativeOrder());
|
m_rotKeys.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
m_scaleKeys = ByteBuffer.allocateDirect(numScaleKeys * 24);
|
m_scaleKeys = ByteBuffer.allocateDirect(numScaleKeys * SCALE_KEY_SIZE);
|
||||||
m_scaleKeys.order(ByteOrder.nativeOrder());
|
m_scaleKeys.order(ByteOrder.nativeOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +140,7 @@ public final class AiNodeAnim {
|
||||||
* Returns the buffer with position keys of this animation channel.<p>
|
* Returns the buffer with position keys of this animation channel.<p>
|
||||||
*
|
*
|
||||||
* Position keys consist of a time value (double) and a position (3D vector
|
* Position keys consist of a time value (double) and a position (3D vector
|
||||||
* of floats), resulting in a total of 24 bytes per entry with padding.
|
* of floats), resulting in a total of 20 bytes per entry.
|
||||||
* The buffer contains {@link #getNumPosKeys()} of these entries.<p>
|
* The buffer contains {@link #getNumPosKeys()} of these entries.<p>
|
||||||
*
|
*
|
||||||
* If there are position keys, there will also be at least one
|
* If there are position keys, there will also be at least one
|
||||||
|
@ -340,7 +339,7 @@ public final class AiNodeAnim {
|
||||||
* Returns the buffer with scaling keys of this animation channel.<p>
|
* Returns the buffer with scaling keys of this animation channel.<p>
|
||||||
*
|
*
|
||||||
* Scaling keys consist of a time value (double) and a 3D vector of floats,
|
* Scaling keys consist of a time value (double) and a 3D vector of floats,
|
||||||
* resulting in a total of 24 bytes per entry with padding. The buffer
|
* resulting in a total of 20 bytes per entry. The buffer
|
||||||
* contains {@link #getNumScaleKeys()} of these entries.<p>
|
* contains {@link #getNumScaleKeys()} of these entries.<p>
|
||||||
*
|
*
|
||||||
* If there are scaling keys, there will also be at least one
|
* If there are scaling keys, there will also be at least one
|
||||||
|
|
|
@ -96,6 +96,13 @@ public final class Jassimp {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of a struct.<p>
|
||||||
|
*
|
||||||
|
* @return the result of sizeof call
|
||||||
|
*/
|
||||||
|
public static native int getVKeysize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a human readable error description.<p>
|
* Returns a human readable error description.<p>
|
||||||
*
|
*
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue