Пример #1
0
Json::Value FileSaver::StoreSkeleton(const SkeletonData& skeleton)
{
	Json::Value value;

	const std::map<ee::SprPtr, std::vector<Joint*> >& map_joints = skeleton.GetMapJoints();
	std::map<ee::SprPtr, std::vector<Joint*> >::const_iterator itr
		= map_joints.begin();
	for (int i = 0; itr != map_joints.end(); ++itr, ++i)
	{
		value[i]["sprite"] = itr->first->GetName();
		for (int j = 0, m = itr->second.size(); j < m; ++j)
		{
			Joint* joint = itr->second[j];

			Json::Value joint_val;
			joint_val["id"] = joint->GetID();
			joint_val["rx"] = joint->GetCurrRelativePos().x;
			joint_val["ry"] = joint->GetCurrRelativePos().y;
			if (const Joint* parent = joint->GetParent()) {
				joint_val["parent"] = parent->GetID();
			}

			const std::set<Joint*>& children = joint->GetChildren();
			std::set<Joint*>::const_iterator itr_child = children.begin();
			for (int k = 0; itr_child != children.end(); ++itr_child, ++k) {
				joint_val["children"][k] = (*itr_child)->GetID();
			}

			value[i]["joints"][j] = joint_val;
		}
	}

	return value;
}
Пример #2
0
    /**
    * Return the TextureDisplay.
    * @example 
    * <listing>
    * var texturedisplay:Object = factory.getTextureDisplay('dragon');
    * </listing>
    * @param    The name of this Texture.
    * @param    The name of the TextureAtlas.
    * @param    The registration pivotX position.
    * @param    The registration pivotY position.
    * @return An Object.
    */
    Object* BaseFactory::getTextureDisplay(const String &textureName, const String &textureAtlasName, Number pivotX, Number pivotY)
    {
        ITextureAtlas* textureAtlas = 0;
        if(!textureAtlasName.empty())
        {
            std::map<String , ITextureAtlas*>::iterator iter = _textureAtlasDic.find(textureAtlasName);
            if(iter != _textureAtlasDic.end())
            {
                textureAtlas = iter->second;
            }
        }
        //if(!textureAtlas && !textureAtlasName)
        //{
        //    for (textureAtlasName in _textureAtlasDic)
        //    {
        //        textureAtlas = _textureAtlasDic[textureAtlasName];
        //        if(textureAtlas.getRegion(textureName))
        //        {
        //            break;
        //        }
        //        textureAtlas = null;
        //    }
        //}
        if(textureAtlas)
        {
            if(isNaN(pivotX) || isNaN(pivotY))
            {
                SkeletonData* data = _dataDic[textureAtlasName];
                if(data)
                {
                    Point *pivot = data->getSubTexturePivot(textureName);
                    if(pivot)
                    {
                        pivotX = pivot->x;
                        pivotY = pivot->y;
                    }
                }
            }

            return generateDisplay(textureAtlas, textureName, pivotX, pivotY);
        }
        return nullptr;
    }
Пример #3
0
    /**
    * Parse the SkeletonData.
    * @param    xml The SkeletonData xml to parse.
    * @return A SkeletonData instance.
    */
    SkeletonData *XMLDataParser::parseSkeletonData(const dragonBones::XMLElement *rootElement)
    {
        String version = rootElement->Attribute(ConstValues::A_VERSION.c_str());
        if(version != DragonBones::DATA_VERSION)
        {
            throw std::invalid_argument("Nonsupport version!");
        }

        uint frameRate = rootElement->IntAttribute(ConstValues::A_FRAME_RATE.c_str());

        SkeletonData *data = new SkeletonData();
        data->name = rootElement->Attribute(ConstValues::A_NAME.c_str());
        for(const dragonBones::XMLElement* armatureXML = rootElement->FirstChildElement(ConstValues::ARMATURE.c_str()) ; armatureXML ; armatureXML = armatureXML->NextSiblingElement(ConstValues::ARMATURE.c_str()))
        {
            data->addArmatureData(parseArmatureData(armatureXML, data, frameRate));
        }

        return data;
    }
SkeletonSprite::SkeletonSprite(const String& filename) : Sprite(NULL) {
	// Cargamos los datos del XML
	SkeletonData* data = new SkeletonData(filename);

    root = new Bone("world", NULL, 0, 0, 0, 0);

	// Generamos huesos
    for ( uint32 i = 0; i < data->GetBoneDatas().Size(); i++ ) {
		// Obtenemos hueso
        const BoneData& boneData = data->GetBoneDatas()[i];
		
		// Obtenemos padre del hueso
        Bone* parent = root;
        if ( boneData.GetParentName() != "world" )
            parent = root->FindChild(boneData.GetParentName());

		// Obtenemos imagen
        Image* image = ResourceManager::Instance().LoadImage(filename.ExtractDir() + "/" + boneData.GetImageFilename());

		// Creamos hueso
        Bone bone(boneData.GetId(), image, boneData.GetPivotX(), boneData.GetPivotY(), boneData.GetHandleX(), boneData.GetHandleY());

		// Aniadimos frames
        for ( uint32 i = 0; i < boneData.GetFrames().Size(); i++ )
            bone.AddFrame(boneData.GetFrames()[i]);

		// Aniadimos hueso
		parent->AddChild(bone);	
	}

	// Establecemos el rango de la animacion
    const Bone* bone = root->GetChild(0);
	int32 lastframe = 0;
	for ( uint32 index = 0; index < bone->CountFrames(); index++ ) {
        lastframe = max(lastframe, bone->GetFrame(index)->GetId());
	}
	SetFrameRange(0, lastframe);

	// Eliminamos los datos cargados del XML
	delete data;
}
Пример #5
0
void RotateSpriteState::Rotate(const sm::vec2& dst)
{
	ee::RotateSpriteState::Rotate(dst);

	SkeletonData* skeleton = get_curr_skeleton();
	if (!skeleton) {
		return;
	}

	ee::SpriteSelection* selection = GetSelection();
	if (selection->IsEmpty()) {
		return;
	}

	std::vector<ee::SprPtr> sprs;
	selection->Traverse(ee::FetchAllRefVisitor<ee::Sprite>(sprs));

	skeleton->FixJoint(sprs[0]);
	float dAngle = sm::get_angle_in_direction(sprs[0]->GetPosition(), GetLastPos(), dst);
	skeleton->UpdateJoint(sprs[0], dAngle);
}
Пример #6
0
SkeletonData* ObjectDataParser::parseSkeletonData(Json::Value & rawData) {

	double version = rawData[ConstValues::A_VERSION].asDouble();

	if (version != DragonBones::DATA_VERSION) {
		printf("[ObjectDataParser] Nonsupport version %f!\n", version);
	}

	unsigned int frameRate = rawData[ConstValues::A_FRAME_RATE].asUInt();

	SkeletonData* data = new SkeletonData();
	data->name = rawData[ConstValues::A_NAME].asCString();

	Json::Value & armature = rawData[ConstValues::ARMATURE];

	printf("armature size %u\n", armature.size());
	for (unsigned int i = 0; i < armature.size(); i++) {
		Json::Value & armatureObject = armature[i];
		data->addArmatureData(parseArmatureData(armatureObject, data, frameRate));
	}

	return data;
}
Пример #7
0
    /**
    * Build and returns a new Armature instance.
    * @example 
    * <listing>
    * var armature:Armature = factory.buildArmature('dragon');
    * </listing>
    * @param    armatureName The name of this Armature instance.
    * @param    The name of this animation
    * @param    The name of this SkeletonData.
    * @param    The name of this textureAtlas.
    * @param    The name of this skin.
    * @return A Armature instance.
    */
    Armature* BaseFactory::buildArmature(const String &armatureName,
                                         const String &animationName,
                                         const String &skeletonName,
                                         const String &textureAtlasName,
                                         const String &skinName)
    {
        ArmatureData* armatureData = 0;
        SkeletonData *data = 0;
        if(!skeletonName.empty())
        {
            std::map<String , SkeletonData*>::iterator iter = _dataDic.find(skeletonName);
            if(iter != _dataDic.end())
            {
                data = iter->second;
                armatureData = data->getArmatureData(armatureName);
            }
        }
        //else
        //{
        //    for(skeletonName in _dataDic)
        //    {
        //        data = _dataDic[skeletonName];
        //        armatureData = data->getArmatureData(armatureName);
        //        if(armatureData)
        //        {
        //            break;
        //        }
        //    }
        //}

        if(!armatureData)
        {
            return nullptr;
        }

        _currentDataName = skeletonName;
        _currentTextureAtlasName = textureAtlasName.empty() ? skeletonName : textureAtlasName;

        Armature* armature = generateArmature();
        armature->name = armatureName;
        Bone* bone;
        for(size_t i = 0 ; i < armatureData->boneDataList.size() ; i ++)
        {
            BoneData* boneData = armatureData->boneDataList[i];
            bone = new Bone();
            bone->name = boneData->name;
            bone->fixedRotation = boneData->fixedRotation;
            bone->scaleMode = boneData->scaleMode;
            bone->origin = boneData->transform;
            if(armatureData->getBoneData(boneData->parent))
            {
                armature->addBone(bone, boneData->parent);
            }
            else
            {
                armature->addBone(bone);
            }
        }

        ArmatureData* animationArmatureData = 0;
        SkinData *skinDataCopy = 0;
        if(!animationName.empty() && animationName != armatureName)
        {
            //ArmatureData* animationArmatureData = data->getArmatureData(animationName);
            // Get the default animation
            //if(!animationArmatureData)
            //{
            //    for (skeletonName in _dataDic)
            //    {
            //        data = _dataDic[skeletonName];
            //        animationArmatureData = data->getArmatureData(animationName);
            //        if(animationArmatureData)
            //        {
            //            break;
            //        }
            //    }
            //}

            ArmatureData* armatureDataCopy = data->getArmatureData(animationName);
            if(armatureDataCopy)
            {
                skinDataCopy = armatureDataCopy->getSkinData("");
            }
        }

        if(animationArmatureData)
        {
            armature->getAnimation()->setAnimationDataList(animationArmatureData->animationDataList);
        }
        else
        {
            armature->getAnimation()->setAnimationDataList(armatureData->animationDataList);
        }

        SkinData* skinData = armatureData->getSkinData(skinName);
        if(!skinData)
        {
            return nullptr;
            //throw new ArgumentError();
        }

        Slot* slot;
        DisplayData* displayData;
        Armature* childArmature;
        size_t i;
        //var helpArray:Array = [];
        for(size_t j = 0 ; j < skinData->slotDataList.size() ; j ++)
        {
            SlotData* slotData = skinData->slotDataList[j];
            bone = armature->getBone(slotData->parent);
            if(!bone)
            {
                continue;
            }
            slot = generateSlot();
            slot->name = slotData->name;
            slot->setBlendMode(slotData->blendMode);
            slot->_originZOrder = slotData->zOrder;
            slot->_dislayDataList = slotData->displayDataList;

            std::vector<Object*> helpArray;

            i = slotData->displayDataList.size();
            helpArray.resize(i);
            while(i --)
            {
                displayData = slotData->displayDataList[i];

                if(displayData->type == DisplayData::ARMATURE)
                {
                    DisplayData* displayDataCopy = 0;
                    if(skinDataCopy)
                    {
                        SlotData* slotDataCopy = skinDataCopy->getSlotData(slotData->name);
                        if(slotDataCopy)
                        {
                            displayDataCopy = slotDataCopy->displayDataList[i];
                        }
                    }
                    else
                    {
                        displayDataCopy = 0;
                    }

                    childArmature = buildArmature(displayData->name, displayDataCopy?displayDataCopy->name:"", _currentDataName, _currentTextureAtlasName);
                    if(childArmature)
                    {
                        helpArray[i] = childArmature;
                    }
				   //fix by Wayne Dimart:
                   // break; we don't use break here, or will crach the program due to incomplete helpArray.
					continue;
                }
                else
                {
                    helpArray[i] = generateDisplay(getTextureAtlas(_currentTextureAtlasName), displayData->name, displayData->pivot.x, displayData->pivot.y);
                }
            }
            slot->setDisplayList(helpArray);
            slot->changeDisplay(0);
            bone->addChild(slot);
        }

        //
        i = armature->_boneList.size();
        while(i --)
        {
            armature->_boneList[i]->update();
        }

        i = armature->_slotList.size();
        while(i --)
        {
            slot = armature->_slotList[i];
            slot->update();
        }
        armature->updateSlotsZOrder();

        return armature;
    }
Пример #8
0
void SkeletonReader::run() {
	cout << " SkeletonReader" << endl;
	while (!stoploop) {
		//Checking if the bottle is good
		bot = in->read();
		if (bot != NULL) {
			if (bot->size() > 0) {
				SkeletonData* sd = new SkeletonData();
				//Creating a new ObjectData object and storing it in the DataCollector
				//Parses the Bottle created by the emulator
				if (emulator) {
					sd->setTimestamp(bot->get(0).asDouble());
					for (int i = 1; i < bot->size(); i++) {
						if (bot->get(i).asString() == "Head") {
							sd->setHeadX(bot->get(i + 2).asDouble());
							sd->setHeadY(bot->get(i + 3).asDouble());
							sd->setHeadZ(bot->get(i + 4).asDouble());
							if (i + 5 < bot->size()) {
								if (bot->get(i + 5).asString()
										== "Orientation") {
									double tmp[ARRAY_SIZE] = {
											bot->get(i + 7).asDouble(),
											bot->get(i + 8).asDouble(),
											bot->get(i + 9).asDouble(),
											bot->get(i + 10).asDouble(),
											bot->get(i + 11).asDouble(),
											bot->get(i + 12).asDouble(),
											bot->get(i + 13).asDouble(),
											bot->get(i + 14).asDouble(),
											bot->get(i + 15).asDouble() };
									vector<double> orientation;
									orientation.insert(orientation.begin(), tmp,
											tmp + ARRAY_SIZE);
									sd->setHeadOrientation(orientation);
								}
							}
						} else if (bot->get(i).asString() == "Left_Hand") {
							sd->setLeftHandX(bot->get(i + 2).asDouble());
							sd->setLeftHandY(bot->get(i + 3).asDouble());
							sd->setLeftHandZ(bot->get(i + 4).asDouble());
							if (i + 5 < bot->size()) {
								if (bot->get(i + 5).asString()
										== "Orientation") {
									double tmp[ARRAY_SIZE] = {
											bot->get(i + 7).asDouble(),
											bot->get(i + 8).asDouble(),
											bot->get(i + 9).asDouble(),
											bot->get(i + 10).asDouble(),
											bot->get(i + 11).asDouble(),
											bot->get(i + 12).asDouble(),
											bot->get(i + 13).asDouble(),
											bot->get(i + 14).asDouble(),
											bot->get(i + 15).asDouble() };
									vector<double> orientation;
									orientation.insert(orientation.begin(), tmp,
											tmp + ARRAY_SIZE);
									sd->setLeftHandOrientation(orientation);
								}
							}
						} else if (bot->get(i).asString() == "Right_Hand") {
							sd->setRightHandX(bot->get(i + 2).asDouble());
							sd->setRightHandY(bot->get(i + 3).asDouble());
							sd->setRightHandZ(bot->get(i + 4).asDouble());
							if (i + 5 < bot->size()) {
								if (bot->get(i + 5).asString()
										== "Orientation") {
									double tmp[ARRAY_SIZE] = {
											bot->get(i + 7).asDouble(),
											bot->get(i + 8).asDouble(),
											bot->get(i + 9).asDouble(),
											bot->get(i + 10).asDouble(),
											bot->get(i + 11).asDouble(),
											bot->get(i + 12).asDouble(),
											bot->get(i + 13).asDouble(),
											bot->get(i + 14).asDouble(),
											bot->get(i + 15).asDouble() };
									vector<double> orientation;
									orientation.insert(orientation.begin(), tmp,
											tmp + ARRAY_SIZE);
									sd->setRightHandOrientation(orientation);
								}
							}
						} else if (bot->get(i).asString() == "Chest") {
							sd->setChestX(bot->get(i + 2).asDouble());
							sd->setChestY(bot->get(i + 3).asDouble());
							sd->setChestZ(bot->get(i + 4).asDouble());
							if (i + 5 < bot->size()) {
								if (bot->get(i + 5).asString()
										== "Orientation") {
									double tmp[ARRAY_SIZE] = {
											bot->get(i + 7).asDouble(),
											bot->get(i + 8).asDouble(),
											bot->get(i + 9).asDouble(),
											bot->get(i + 10).asDouble(),
											bot->get(i + 11).asDouble(),
											bot->get(i + 12).asDouble(),
											bot->get(i + 13).asDouble(),
											bot->get(i + 14).asDouble(),
											bot->get(i + 15).asDouble() };
									vector<double> orientation;
									orientation.insert(orientation.begin(), tmp,
											tmp + ARRAY_SIZE);
									sd->setChestOrientation(orientation);
								}
							}
						}
					}
				} else {
					//Creating a new ObjectData object and storing it in the DataCollector
					//Parses the Bottle created by the KinectDeviceLocal of yarp
					in->getEnvelope(time);
					sd->setTimestamp(time.getTime());
					Bottle pos;
					int j = 0;
					for (int i = 0; i < bot->size(); i++) {
						switch (bot->get(i).asInt()) {
						case VOCAB3('P','O','S'):
							switch (j) {
							case HEAD_POS:
								sd->setHeadX(
										bot->get(i + 1).asList()->get(0).asDouble());
								sd->setHeadY(
										bot->get(i + 1).asList()->get(1).asDouble());
								sd->setHeadZ(
										bot->get(i + 1).asList()->get(2).asDouble());
								break;
							case CHEST_POS:
								sd->setChestX(
										bot->get(i + 1).asList()->get(0).asDouble());
								sd->setChestY(
										bot->get(i + 1).asList()->get(1).asDouble());
								sd->setChestZ(
										bot->get(i + 1).asList()->get(2).asDouble());
								break;
							case LEFT_HAND_POS:
								sd->setLeftHandX(
										bot->get(i + 1).asList()->get(0).asDouble());
								sd->setLeftHandY(
										bot->get(i + 1).asList()->get(1).asDouble());
								sd->setLeftHandZ(
										bot->get(i + 1).asList()->get(2).asDouble());
								break;
							case RIGHT_HAND_POS:
								sd->setRightHandX(
										bot->get(i + 1).asList()->get(0).asDouble());
								sd->setRightHandY(
										bot->get(i + 1).asList()->get(1).asDouble());
								sd->setRightHandZ(
										bot->get(i + 1).asList()->get(2).asDouble());
								break;
							}
							j++;
							break;
						}
					}
				}
				parent->addSkeletonData(sd);
			}
		}
	}
}
Пример #9
0
SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, const int length) {
	bool nonessential;
	SkeletonData *skeletonData;

	DataInput *input = new(__FILE__, __LINE__) DataInput();
	input->cursor = binary;
	input->end = binary + length;

	_linkedMeshes.clear();

	skeletonData = new(__FILE__, __LINE__) SkeletonData();

	char *skeletonData_hash = readString(input);
	skeletonData->_hash.own(skeletonData_hash);

	char *skeletonData_version = readString(input);
	skeletonData->_version.own(skeletonData_version);

	skeletonData->_width = readFloat(input);
	skeletonData->_height = readFloat(input);

	nonessential = readBoolean(input);

	if (nonessential) {
		/* Skip images path, audio path & fps */
		skeletonData->_fps = readFloat(input);
		skeletonData->_imagesPath.own(readString(input));
		skeletonData->_audioPath.own(readString(input));
	}

	/* Bones. */
	int numBones = readVarint(input, true);
	skeletonData->_bones.setSize(numBones, 0);
	for (int i = 0; i < numBones; ++i) {
		const char *name = readString(input);
		BoneData *parent = i == 0 ? 0 : skeletonData->_bones[readVarint(input, true)];
		BoneData *data = new(__FILE__, __LINE__) BoneData(i, String(name, true), parent);
		data->_rotation = readFloat(input);
		data->_x = readFloat(input) * _scale;
		data->_y = readFloat(input) * _scale;
		data->_scaleX = readFloat(input);
		data->_scaleY = readFloat(input);
		data->_shearX = readFloat(input);
		data->_shearY = readFloat(input);
		data->_length = readFloat(input) * _scale;
		data->_transformMode = static_cast<TransformMode>(readVarint(input, true));
		if (nonessential) {
			/* Skip bone color. */
			readInt(input);
		}
		skeletonData->_bones[i] = data;
	}

	/* Slots. */
	int slotsCount = readVarint(input, true);
	skeletonData->_slots.setSize(slotsCount, 0);
	for (int i = 0; i < slotsCount; ++i) {
		const char *slotName = readString(input);
		BoneData *boneData = skeletonData->_bones[readVarint(input, true)];
		SlotData *slotData = new(__FILE__, __LINE__) SlotData(i, String(slotName, true), *boneData);

		readColor(input, slotData->getColor());
		unsigned char r = readByte(input);
		unsigned char g = readByte(input);
		unsigned char b = readByte(input);
		unsigned char a = readByte(input);
		if (!(r == 0xff && g == 0xff && b == 0xff && a == 0xff)) {
			slotData->getDarkColor().set(r / 255.0f, g / 255.0f, b / 255.0f, 1);
			slotData->setHasDarkColor(true);
		}
		slotData->_attachmentName.own(readString(input));
		slotData->_blendMode = static_cast<BlendMode>(readVarint(input, true));
		skeletonData->_slots[i] = slotData;
	}

	/* IK constraints. */
	int ikConstraintsCount = readVarint(input, true);
	skeletonData->_ikConstraints.setSize(ikConstraintsCount, 0);
	for (int i = 0; i < ikConstraintsCount; ++i) {
		const char *name = readString(input);
		IkConstraintData *data = new(__FILE__, __LINE__) IkConstraintData(String(name, true));
		data->_order = readVarint(input, true);
		int bonesCount = readVarint(input, true);
		data->_bones.setSize(bonesCount, 0);
		for (int ii = 0; ii < bonesCount; ++ii) {
			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
		}
		data->_target = skeletonData->_bones[readVarint(input, true)];
		data->_mix = readFloat(input);
		data->_bendDirection = readSByte(input);
		data->_compress = readBoolean(input);
		data->_stretch = readBoolean(input);
		data->_uniform = readBoolean(input);
		skeletonData->_ikConstraints[i] = data;
	}

	/* Transform constraints. */
	int transformConstraintsCount = readVarint(input, true);
	skeletonData->_transformConstraints.setSize(transformConstraintsCount, 0);
	for (int i = 0; i < transformConstraintsCount; ++i) {
		const char *name = readString(input);
		TransformConstraintData *data = new(__FILE__, __LINE__) TransformConstraintData(String(name, true));
		data->_order = readVarint(input, true);
		int bonesCount = readVarint(input, true);
		data->_bones.setSize(bonesCount, 0);
		for (int ii = 0; ii < bonesCount; ++ii) {
			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
		}
		data->_target = skeletonData->_bones[readVarint(input, true)];
		data->_local = readBoolean(input);
		data->_relative = readBoolean(input);
		data->_offsetRotation = readFloat(input);
		data->_offsetX = readFloat(input) * _scale;
		data->_offsetY = readFloat(input) * _scale;
		data->_offsetScaleX = readFloat(input);
		data->_offsetScaleY = readFloat(input);
		data->_offsetShearY = readFloat(input);
		data->_rotateMix = readFloat(input);
		data->_translateMix = readFloat(input);
		data->_scaleMix = readFloat(input);
		data->_shearMix = readFloat(input);
		skeletonData->_transformConstraints[i] = data;
	}

	/* Path constraints */
	int pathConstraintsCount = readVarint(input, true);
	skeletonData->_pathConstraints.setSize(pathConstraintsCount, 0);
	for (int i = 0; i < pathConstraintsCount; ++i) {
		const char *name = readString(input);
		PathConstraintData *data = new(__FILE__, __LINE__) PathConstraintData(String(name, true));
		data->_order = readVarint(input, true);
		int bonesCount = readVarint(input, true);
		data->_bones.setSize(bonesCount, 0);
		for (int ii = 0; ii < bonesCount; ++ii) {
			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
		}
		data->_target = skeletonData->_slots[readVarint(input, true)];
		data->_positionMode = static_cast<PositionMode>(readVarint(input, true));
		data->_spacingMode = static_cast<SpacingMode>(readVarint(input, true));
		data->_rotateMode = static_cast<RotateMode>(readVarint(input, true));
		data->_offsetRotation = readFloat(input);
		data->_position = readFloat(input);
		if (data->_positionMode == PositionMode_Fixed) data->_position *= _scale;
		data->_spacing = readFloat(input);
		if (data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed)
			data->_spacing *= _scale;
		data->_rotateMix = readFloat(input);
		data->_translateMix = readFloat(input);
		skeletonData->_pathConstraints[i] = data;
	}

	/* Default skin. */
	skeletonData->_defaultSkin = readSkin(input, "default", skeletonData, nonessential);
	int skinsCount = readVarint(input, true);
	if (skeletonData->_defaultSkin) {
		++skinsCount;
	}
	skeletonData->_skins.setSize(skinsCount, 0);
	if (skeletonData->_defaultSkin) {
		skeletonData->_skins[0] = skeletonData->_defaultSkin;
	}

	/* Skins. */
	for (size_t i = skeletonData->_defaultSkin ? 1 : 0; i < skeletonData->_skins.size(); ++i) {
		String skinName(readString(input), true);
		skeletonData->_skins[i] = readSkin(input, skinName, skeletonData, nonessential);
	}

	/* Linked meshes. */
	for (int i = 0, n = _linkedMeshes.size(); i < n; ++i) {
		LinkedMesh *linkedMesh = _linkedMeshes[i];
		Skin *skin = linkedMesh->_skin.length() == 0 ? skeletonData->getDefaultSkin() : skeletonData->findSkin(
				linkedMesh->_skin);
		if (skin == NULL) {
			delete input;
			delete skeletonData;
			setError("Skin not found: ", linkedMesh->_skin.buffer());
			return NULL;
		}
		Attachment *parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent);
		if (parent == NULL) {
			delete input;
			delete skeletonData;
			setError("Parent mesh not found: ", linkedMesh->_parent.buffer());
			return NULL;
		}
		linkedMesh->_mesh->setParentMesh(static_cast<MeshAttachment *>(parent));
		linkedMesh->_mesh->updateUVs();
		_attachmentLoader->configureAttachment(linkedMesh->_mesh);
	}
	ContainerUtil::cleanUpVectorOfPointers(_linkedMeshes);
	_linkedMeshes.clear();

	/* Events. */
	int eventsCount = readVarint(input, true);
	skeletonData->_events.setSize(eventsCount, 0);
	for (int i = 0; i < eventsCount; ++i) {
		const char *name = readString(input);
		EventData *eventData = new(__FILE__, __LINE__) EventData(String(name, true));
		eventData->_intValue = readVarint(input, false);
		eventData->_floatValue = readFloat(input);
		eventData->_stringValue.own(readString(input));
		eventData->_audioPath.own(readString(input)); // skip audio path
		if (!eventData->_audioPath.isEmpty()) {
			eventData->_volume = readFloat(input);
			eventData->_balance = readFloat(input);
		}
		skeletonData->_events[i] = eventData;
	}

	/* Animations. */
	int animationsCount = readVarint(input, true);
	skeletonData->_animations.setSize(animationsCount, 0);
	for (int i = 0; i < animationsCount; ++i) {
		String name(readString(input), true);
		Animation *animation = readAnimation(name, input, skeletonData);
		if (!animation) {
			delete input;
			delete skeletonData;
			return NULL;
		}
		skeletonData->_animations[i] = animation;
	}

	delete input;
	return skeletonData;
}