On 30/12/2015 at 11:56, xxxxxxxx wrote:
Hi Yannick,
Thanks for your reply.
Your solution is working but it means that I have to calculate the whole scene for each frames (which is not acceptable).
My initial goal was to retrieve the corresponding bitmap file for image sequences bitmap (Xbitmap) on a given frame.
https://plugincafe.maxon.net/topic/8970/11903_getting-the-frame-from-movie-in-material-solved&KW=bitmap+animation&PID=46991#46991
I wrote a method that return the corresponding file depending on the frame and the bitmap parameters (mode, timing, range start/end, loops, movie start/end/rate).
But knowing that all these parameters are keyframable, if I want to get all images in a frame range, I have to run the method on each frames.
I tried with CCurve::AddKeyAdaptTangent to add a keyframe on each frame to avoid interpolation calculation, but it doesn't works for BaseTime.
Since the animation parameters of Xbitmap are either Int or BaseTime I end up with something like that for the interpolation calculation:
const GeData utils::GetFrameData(BaseList2D* op, const BaseTime& time, Int32 id)
{
Int32 type = op->GetData().GetType(id);
DescID descID = DescID(DescLevel(id, type, 0));
CTrack *track = op->FindCTrack(descID);
if (track)
{
CCurve *curve = track->GetCurve();
GeData data;
// Interpolated types
switch (type)
{
case DA_LONG:
data.SetInt32(curve->GetValue(time));
return data;
case DA_REAL:
data.SetFloat(curve->GetValue(time));
return data;
case DA_LLONG:
data.SetInt64(curve->GetValue(time));
return data;
case DA_TIME:
data.SetBaseTime(utils::GetInterpolatedValue(curve, time).GetTime());
return data;
}
// Un-interpolated types
CKey* key = curve->FindKey(time, nullptr, FINDANIM_LEFT);
if (key)
return utils::GetKeyValue(key);
key = curve->FindKey(time, nullptr, FINDANIM_RIGHT);
if (key)
return utils::GetKeyValue(key);
}
return op->GetDataInstance()->GetData(id);
}
const GeData utils::GetInterpolatedValue(CCurve* curve, const BaseTime& time)
{
CKey* key = curve->FindKey(time, nullptr, FINDANIM_EXACT);
// Exact keyframe
if (key)
return utils::GetKeyValue(key);
CKey* left = curve->FindKey(time, nullptr, FINDANIM_LEFT);
CKey* right = curve->FindKey(time, nullptr, FINDANIM_RIGHT);
// Left or right
if (!right ^ !left)
return utils::GetKeyValue((left ? left : right));
// Both
if (left && right)
{
GeData data = utils::GetKeyValue(left);
if (left->GetInterpolation() == CINTERPOLATION_STEP)
return data;
if (data.GetType() == DA_TIME)
{
const Int32 dummyFps = 30;
Float start = left->GetTime().GetFrame(dummyFps);
Float end = right->GetTime().GetFrame(dummyFps);
Float current = time.GetFrame(dummyFps);
Float mix = (current - start) / (end - start);
start = data.GetTime().GetFrame(dummyFps);
end = utils::GetKeyValue(right).GetTime().GetFrame(dummyFps);
Float interpolated = (end * mix) + (start * (1.0 - mix));
data.SetBaseTime(BaseTime(interpolated, dummyFps));
}
return data;
}
return GeData();
}
GeData utils::GetKeyValue(CKey* key)
{
GeData data;
key->GetParameter(DescLevel(ID_CKEY_VALUE), data, DESCFLAGS_GET_0);
return data;
}
I use CCurve::GetValue for real types and a custom function for BaseTime (grabbing the previous and next frame to calculate the interpolation).
It's not very generic but it is suitable for my needs.
I need to test it more to see if it works in all cases.
By the way, thank you for the tips you gave me at the C4Day regarding unit tests, I'm currently implementing unit tests with Google Test and it seems to works well!