mirror of https://github.com/axmolengine/axmol.git
345 lines
10 KiB
C++
345 lines
10 KiB
C++
#include "BaseTimelineState.h"
|
|
#include "../model/DragonBonesData.h"
|
|
#include "../model/ArmatureData.h"
|
|
#include "../model/AnimationData.h"
|
|
#include "../armature/Armature.h"
|
|
#include "../armature/Bone.h"
|
|
#include "../armature/Slot.h"
|
|
#include "AnimationState.h"
|
|
#include "TimelineState.h"
|
|
|
|
#include <math.h>
|
|
|
|
DRAGONBONES_NAMESPACE_BEGIN
|
|
|
|
void TimelineState::_onClear()
|
|
{
|
|
playState = -1;
|
|
currentPlayTimes = -1;
|
|
currentTime = -1.0f;
|
|
|
|
_tweenState = TweenState::None;
|
|
_frameRate = 0;
|
|
_frameValueOffset = 0;
|
|
_frameCount = 0;
|
|
_frameOffset = 0;
|
|
_frameIndex = -1;
|
|
_frameRateR = 0.0f;
|
|
_position = 0.0f;
|
|
_duration = 0.0f;
|
|
_timeScale = 1.0f;
|
|
_timeOffset = 0.0f;
|
|
_dragonBonesData = nullptr;
|
|
_animationData = nullptr;
|
|
_timelineData = nullptr;
|
|
_armature = nullptr;
|
|
_animationState = nullptr;
|
|
_actionTimeline = nullptr;
|
|
_frameArray = nullptr;
|
|
_frameIntArray = nullptr;
|
|
_frameFloatArray = nullptr;
|
|
_timelineArray = nullptr;
|
|
_frameIndices = nullptr;
|
|
}
|
|
|
|
bool TimelineState::_setCurrentTime(float passedTime)
|
|
{
|
|
const auto prevState = playState;
|
|
const auto prevPlayTimes = currentPlayTimes;
|
|
const auto prevTime = currentTime;
|
|
|
|
if (_actionTimeline != nullptr && _frameCount <= 1) // No frame or only one frame.
|
|
{
|
|
playState = _actionTimeline->playState >= 0 ? 1 : -1;
|
|
currentPlayTimes = 1;
|
|
currentTime = _actionTimeline->currentTime;
|
|
}
|
|
else if (_actionTimeline == nullptr || _timeScale != 1.0f || _timeOffset != 0.0f) // Action timeline or has scale and offset.
|
|
{
|
|
const auto playTimes = _animationState->playTimes;
|
|
const auto totalTime = playTimes * _duration;
|
|
|
|
passedTime *= _timeScale;
|
|
if (_timeOffset != 0.0f)
|
|
{
|
|
passedTime += _timeOffset * _animationData->duration;
|
|
}
|
|
|
|
if (playTimes > 0 && (passedTime >= totalTime || passedTime <= -totalTime))
|
|
{
|
|
if (playState <= 0 && _animationState->_playheadState == 3)
|
|
{
|
|
playState = 1;
|
|
}
|
|
|
|
currentPlayTimes = playTimes;
|
|
if (passedTime < 0.0f)
|
|
{
|
|
currentTime = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
currentTime = _duration + 0.000001f; // Precision problem
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (playState != 0 && _animationState->_playheadState == 3)
|
|
{
|
|
playState = 0;
|
|
}
|
|
|
|
if (passedTime < 0.0f)
|
|
{
|
|
passedTime = -passedTime;
|
|
currentPlayTimes = (int)(passedTime / _duration);
|
|
currentTime = _duration - fmod(passedTime, _duration);
|
|
}
|
|
else
|
|
{
|
|
currentPlayTimes = (int)(passedTime / _duration);
|
|
currentTime = fmod(passedTime, _duration);
|
|
}
|
|
}
|
|
|
|
currentTime += _position;
|
|
}
|
|
else // Multi frames.
|
|
{
|
|
playState = _actionTimeline->playState;
|
|
currentPlayTimes = _actionTimeline->currentPlayTimes;
|
|
currentTime = _actionTimeline->currentTime;
|
|
}
|
|
|
|
if (currentPlayTimes == prevPlayTimes && currentTime == prevTime)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Clear frame flag when timeline start or loopComplete.
|
|
if (
|
|
(prevState < 0 && playState != prevState) ||
|
|
(playState <= 0 && currentPlayTimes != prevPlayTimes)
|
|
)
|
|
{
|
|
_frameIndex = -1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void TimelineState::init(Armature* armature, AnimationState* animationState, TimelineData* timelineData)
|
|
{
|
|
_armature = armature;
|
|
_animationState = animationState;
|
|
_timelineData = timelineData;
|
|
_actionTimeline = _animationState->_actionTimeline;
|
|
|
|
if (this == _actionTimeline)
|
|
{
|
|
_actionTimeline = nullptr; //
|
|
}
|
|
|
|
_animationData = _animationState->_animationData;
|
|
|
|
_frameRate = _animationData->parent->frameRate;
|
|
_frameRateR = 1.0f / _frameRate;
|
|
_position = _animationState->_position;
|
|
_duration = _animationState->_duration;
|
|
_dragonBonesData = _animationData->parent->parent;
|
|
|
|
if (_timelineData != nullptr)
|
|
{
|
|
_frameIntArray = _dragonBonesData->frameIntArray;
|
|
_frameFloatArray = _dragonBonesData->frameFloatArray;
|
|
_frameArray = _dragonBonesData->frameArray;
|
|
_timelineArray = _dragonBonesData->timelineArray;
|
|
_frameIndices = &(_dragonBonesData->frameIndices);
|
|
|
|
_frameCount = _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineKeyFrameCount];
|
|
_frameValueOffset = _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineFrameValueOffset];
|
|
_timeScale = 100.0f / _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineScale];
|
|
_timeOffset = _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineOffset] * 0.01f;
|
|
}
|
|
}
|
|
|
|
void TimelineState::update(float passedTime)
|
|
{
|
|
if (_setCurrentTime(passedTime))
|
|
{
|
|
if (_frameCount > 1)
|
|
{
|
|
const auto timelineFrameIndex = (unsigned)(currentTime * _frameRate);
|
|
const auto frameIndex = (*_frameIndices)[_timelineData->frameIndicesOffset + timelineFrameIndex];
|
|
if ((unsigned)_frameIndex != frameIndex)
|
|
{
|
|
_frameIndex = frameIndex;
|
|
_frameOffset = _animationData->frameOffset + _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineFrameOffset + _frameIndex];
|
|
|
|
_onArriveAtFrame();
|
|
}
|
|
}
|
|
else if (_frameIndex < 0)
|
|
{
|
|
_frameIndex = 0;
|
|
if (_timelineData != nullptr) // May be pose timeline.
|
|
{
|
|
_frameOffset = _animationData->frameOffset + _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineFrameOffset];
|
|
}
|
|
|
|
_onArriveAtFrame();
|
|
}
|
|
|
|
if (_tweenState != TweenState::None)
|
|
{
|
|
_onUpdateFrame();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TweenTimelineState::_onClear()
|
|
{
|
|
TimelineState::_onClear();
|
|
|
|
_tweenType = TweenType::None;
|
|
_curveCount = 0;
|
|
_framePosition = 0.0f;
|
|
_frameDurationR = 0.0f;
|
|
_tweenProgress = 0.0f;
|
|
_tweenEasing = 0.0f;
|
|
}
|
|
|
|
void TweenTimelineState::_onArriveAtFrame()
|
|
{
|
|
if (
|
|
_frameCount > 1 &&
|
|
(
|
|
(unsigned)_frameIndex != _frameCount - 1 ||
|
|
_animationState->playTimes == 0 ||
|
|
_animationState->getCurrentPlayTimes() < _animationState->playTimes - 1
|
|
)
|
|
)
|
|
{
|
|
_tweenType = (TweenType)_frameArray[_frameOffset + (unsigned)BinaryOffset::FrameTweenType]; // TODO recode ture tween type.
|
|
_tweenState = _tweenType == TweenType::None ? TweenState::Once : TweenState::Always;
|
|
|
|
if (_tweenType == TweenType::Curve)
|
|
{
|
|
_curveCount = _frameArray[_frameOffset + (unsigned)BinaryOffset::FrameTweenEasingOrCurveSampleCount];
|
|
}
|
|
else if (_tweenType != TweenType::None && _tweenType != TweenType::Line)
|
|
{
|
|
_tweenEasing = _frameArray[_frameOffset + (unsigned)BinaryOffset::FrameTweenEasingOrCurveSampleCount] * 0.01;
|
|
}
|
|
|
|
_framePosition = _frameArray[_frameOffset] * _frameRateR;
|
|
|
|
if ((unsigned)_frameIndex == _frameCount - 1)
|
|
{
|
|
_frameDurationR = 1.0f / (_animationData->duration - _framePosition);
|
|
}
|
|
else
|
|
{
|
|
const auto nextFrameOffset = _animationData->frameOffset + _timelineArray[_timelineData->offset + (unsigned)BinaryOffset::TimelineFrameOffset + _frameIndex + 1];
|
|
const auto frameDuration = _frameArray[nextFrameOffset] * _frameRateR - _framePosition;
|
|
|
|
if (frameDuration > 0.0f) // Fixed animation data bug.
|
|
{
|
|
_frameDurationR = 1.0f / frameDuration;
|
|
}
|
|
else
|
|
{
|
|
_frameDurationR = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_tweenState = TweenState::Once;
|
|
}
|
|
}
|
|
|
|
void TweenTimelineState::_onUpdateFrame()
|
|
{
|
|
if (_tweenState == TweenState::Always)
|
|
{
|
|
_tweenProgress = (currentTime - _framePosition) * _frameDurationR;
|
|
|
|
if (_tweenType == TweenType::Curve)
|
|
{
|
|
_tweenProgress = TweenTimelineState::_getEasingCurveValue(_tweenProgress, _frameArray, _curveCount, _frameOffset + (unsigned)BinaryOffset::FrameCurveSamples);
|
|
}
|
|
else if (_tweenType != TweenType::Line)
|
|
{
|
|
_tweenProgress = TweenTimelineState::_getEasingValue(_tweenType, _tweenProgress, _tweenEasing);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_tweenProgress = 0.0f;
|
|
}
|
|
}
|
|
|
|
void BoneTimelineState::_onClear()
|
|
{
|
|
TweenTimelineState::_onClear();
|
|
|
|
bone = nullptr;
|
|
bonePose = nullptr;
|
|
}
|
|
|
|
void BoneTimelineState::blend(int state)
|
|
{
|
|
const auto blendWeight = bone->_blendState.blendWeight;
|
|
auto& animationPose = bone->animationPose;
|
|
const auto& result = bonePose->result;
|
|
|
|
if (state == 2)
|
|
{
|
|
animationPose.x += result.x * blendWeight;
|
|
animationPose.y += result.y * blendWeight;
|
|
animationPose.rotation += result.rotation * blendWeight;
|
|
animationPose.skew += result.skew * blendWeight;
|
|
animationPose.scaleX += (result.scaleX - 1.0f) * blendWeight;
|
|
animationPose.scaleY += (result.scaleY - 1.0f) * blendWeight;
|
|
}
|
|
else if (blendWeight != 1.0f)
|
|
{
|
|
animationPose.x = result.x * blendWeight;
|
|
animationPose.y = result.y * blendWeight;
|
|
animationPose.rotation = result.rotation * blendWeight;
|
|
animationPose.skew = result.skew * blendWeight;
|
|
animationPose.scaleX = (result.scaleX - 1.0f) * blendWeight + 1.0f;
|
|
animationPose.scaleY = (result.scaleY - 1.0f) * blendWeight + 1.0f;
|
|
}
|
|
else
|
|
{
|
|
animationPose.x = result.x;
|
|
animationPose.y = result.y;
|
|
animationPose.rotation = result.rotation;
|
|
animationPose.skew = result.skew;
|
|
animationPose.scaleX = result.scaleX;
|
|
animationPose.scaleY = result.scaleY;
|
|
}
|
|
|
|
if (_animationState->_fadeState != 0 || _animationState->_subFadeState != 0)
|
|
{
|
|
bone->_transformDirty = true;
|
|
}
|
|
}
|
|
|
|
void SlotTimelineState::_onClear()
|
|
{
|
|
TweenTimelineState::_onClear();
|
|
|
|
slot = nullptr;
|
|
}
|
|
|
|
void ConstraintTimelineState::_onClear()
|
|
{
|
|
TweenTimelineState::_onClear();
|
|
|
|
constraint = nullptr;
|
|
}
|
|
DRAGONBONES_NAMESPACE_END
|