/** @private */
    AnimationData *XMLDataParser::parseAnimationData(const dragonBones::XMLElement *animationXML, ArmatureData *armatureData, uint frameRate)
    {
        AnimationData *animationData = new AnimationData();
        animationData->name = animationXML->Attribute(ConstValues::A_NAME.c_str());
        animationData->frameRate = frameRate;
        animationData->loop = int(animationXML->IntAttribute(ConstValues::A_LOOP.c_str()));
        animationData->setFadeInTime(Number(animationXML->DoubleAttribute(ConstValues::A_FADE_IN_TIME.c_str())));
        animationData->duration = Number(animationXML->DoubleAttribute(ConstValues::A_DURATION.c_str())) / (Number)frameRate;
        animationData->scale = Number(animationXML->DoubleAttribute(ConstValues::A_SCALE.c_str()));
        if(strcmp(animationXML->Attribute(ConstValues::A_TWEEN_EASING.c_str()) , "NaN") == 0)
        {
            animationData->tweenEasing = NaN;
        }
        else
        {
            animationData->tweenEasing = Number(animationXML->DoubleAttribute(ConstValues::A_TWEEN_EASING.c_str()));
        }

        parseTimeline(animationXML, animationData, parseMainFrame, frameRate);

        TransformTimeline *timeline = 0;
        String timelineName;
        for(const dragonBones::XMLElement* timelineXML = animationXML->FirstChildElement(ConstValues::TIMELINE.c_str()) ; timelineXML ; timelineXML = timelineXML->NextSiblingElement(ConstValues::TIMELINE.c_str()))
        {
            timeline = parseTransformTimeline(timelineXML, animationData->duration, frameRate);
            timelineName = timelineXML->Attribute(ConstValues::A_NAME.c_str());
            animationData->addTimeline(timeline, timelineName);
        }

        DBDataUtil::addHideTimeline(animationData, armatureData);
        DBDataUtil::transformAnimationData(animationData, armatureData);

        return animationData;
    }
    TransformTimeline *XMLDataParser::parseTransformTimeline(const dragonBones::XMLElement *timelineXML, Number duration, uint frameRate)
    {
        TransformTimeline *timeline = new TransformTimeline();
        timeline->duration = duration;

        parseTimeline(timelineXML, timeline, parseTransformFrame, frameRate);

        timeline->scale = Number(timelineXML->DoubleAttribute(ConstValues::A_SCALE.c_str()));
        timeline->offset = Number(timelineXML->DoubleAttribute(ConstValues::A_OFFSET.c_str()));

        return timeline;
    }
// 解析出DB骨骼数据
DragonBonesData* DotaAnimParser::parseDragonBonesData(
	Dota_Skeleton_Data& dotaSkeletonData,
	ITextureAtlas& textureAtlas, float scale/* = 1.f*/)
{
	_armatureScale = scale;
    _frameRate = 24;

    DragonBonesData *dragonBonesData = new DragonBonesData();
    dragonBonesData->name = dotaSkeletonData.name;
    
	ArmatureData *armatureData = new ArmatureData();
	armatureData->name = dotaSkeletonData.name;

	for (int i = 0; i < (int)dotaSkeletonData.boneDataList.size(); i++)
	{
		Dota_Bone_Data * dotaBoneData = dotaSkeletonData.boneDataList[i];

		BoneData *boneData = new BoneData();

		boneData->name = dotaBoneData->name;

		boneData->length = 0;
		boneData->inheritRotation = true;
		boneData->inheritScale = false;

		Dota_Slot_Data * slotData = nullptr;
		Dota_First_Frame_Data::iterator iter;
		iter = dotaSkeletonData.firstFrameOfBoneMap.find(dotaBoneData->name);
		if (iter != dotaSkeletonData.firstFrameOfBoneMap.end())
			slotData = iter->second;

		if (slotData != nullptr)
			setTransform(boneData->global, slotData->x, slotData->y, 
				slotData->skX, slotData->skY, slotData->scX, slotData->scY);
		else
			setTransform(boneData->global, 0, 0, 0, 0, 1, 1);
		
		boneData->transform = boneData->global;

		armatureData->boneDataList.push_back(boneData);
	}

	SkinData *skinData = new SkinData();
	skinData->name = "default";

	for (int i = 0; i < (int)dotaSkeletonData.boneDataList.size(); i++)
	{
		Dota_Bone_Data * dotaBoneData = dotaSkeletonData.boneDataList[i];

		SlotData *slotData = new SlotData();
		slotData->name = dotaBoneData->name;
		slotData->parent = dotaBoneData->name;
		slotData->zOrder = dotaBoneData->index;

		DisplayData *displayData = new DisplayData();
		displayData->name = dotaBoneData->textureName + ".png";
		displayData->type = DisplayType::DT_IMAGE;
		displayData->scalingGrid = false;
		
		setTransform(displayData->transform, 0, 0, 0, 0, 1, 1);
		
		TextureData * textureData = getTextureData(textureAtlas, displayData->name);
		if (textureData->rotated)
		{
			displayData->pivot.x = textureData->region.height / 2 / _armatureScale;
			displayData->pivot.y = textureData->region.width / 2 / _armatureScale;
		}
		else
		{
			displayData->pivot.x = textureData->region.width / 2 / _armatureScale;
			displayData->pivot.y = textureData->region.height / 2 / _armatureScale;
		}

		slotData->displayDataList.push_back(displayData);
		skinData->slotDataList.push_back(slotData);
	}
	armatureData->skinDataList.push_back(skinData);

	transformArmatureData(armatureData);
	armatureData->sortBoneDataList();

	for (int i = 0; i < (int)dotaSkeletonData.animDataList.size(); i++)
	{
		Dota_Anim_Data * dotaAnimData = dotaSkeletonData.animDataList[i];

		AnimationData *animationData = new AnimationData();
		animationData->name = dotaAnimData->name;
		animationData->frameRate = _frameRate;
		animationData->duration = (int)(round((int)dotaAnimData->frameDataList.size() * 1000.f / _frameRate));
		animationData->playTimes = 0;
		animationData->fadeTime = 0.f;	//0.3f;
		animationData->scale = 1;
		// use frame tweenEase, NaN
		// overwrite frame tweenEase, [-1, 0):ease in, 0:line easing, (0, 1]:ease out, (1, 2]:ease in out
		animationData->tweenEasing = USE_FRAME_TWEEN_EASING;
		animationData->autoTween = true;

		parseTimeline(*animationData);


		std::map<std::string, Dota_Anim_Data2 *>::iterator iter;
		iter = dotaSkeletonData.animDataMap.find(dotaAnimData->name);
		if (iter == dotaSkeletonData.animDataMap.end())
			continue;

		Dota_Anim_Data2 * dotaAnimData2 = iter->second;

		Dota_Anim_Data2::iterator iter2;
		for (iter2 = dotaAnimData2->begin(); iter2 != dotaAnimData2->end(); iter2++)
		{
			Dota_Timeline_Data * dataTimelineData2 = iter2->second;

			TransformTimeline *timeline = new TransformTimeline();
			timeline->name = iter2->first;
			timeline->scale = 1;
			timeline->offset = 0;
			timeline->duration = animationData->duration;

			int nBlankKeyframes = 0;
			for (int j = 0; j < (int)dotaAnimData->frameDataList.size(); j++)
			{	
				Dota_Timeline_Data::iterator iter3 = dataTimelineData2->find(toString(j));
				if (iter3 != dataTimelineData2->end())
				{
					Dota_Slot_Data * slotData = iter3->second;

					if (nBlankKeyframes > 0)
					{
						TransformFrame *frame = newBlankKeyframes(nBlankKeyframes, slotData->soundName);
						timeline->frameList.push_back(frame);
						nBlankKeyframes = 0;
					}

					TransformFrame *frame = newKeyframes(slotData->zOrder, 
						slotData->opacity, slotData->x, slotData->y,
						slotData->skX, slotData->skY, slotData->scX, slotData->scY, 
						slotData->soundName);
					timeline->frameList.push_back(frame);
				}
				else
				{
					nBlankKeyframes++;
				}
			}

			if (nBlankKeyframes > 0)
			{
				TransformFrame *frame = newBlankKeyframes(nBlankKeyframes, "");
				timeline->frameList.push_back(frame);
				nBlankKeyframes = 0;
			}

			parseTimeline(*timeline);

			animationData->timelineList.push_back(timeline);
		}

		addHideTimeline(animationData, armatureData);
		transformAnimationData(animationData, armatureData);

		armatureData->animationDataList.push_back(animationData);
	}

	dragonBonesData->armatureDataList.push_back(armatureData);

    return dragonBonesData;
}