Example #1
0
void PlanarSPQRTree::setPosInEmbedding(
	NodeArray<SListPure<adjEntry> > &adjEdges,
	NodeArray<node> &currentCopy,
	NodeArray<adjEntry> &lastAdj,
	SListPure<node> &current,
	const Skeleton &S,
	adjEntry adj)
{
	node vT = S.treeNode();

	adjEdges[vT].pushBack(adj);

	node vCopy = adj->theNode();
	node vOrig = S.original(vCopy);

	if(currentCopy[vT] == nullptr) {
		currentCopy[vT] = vCopy;
		current.pushBack(vT);

		for (adjEntry adjVirt : vCopy->adjEdges) {
			edge eCopy = S.twinEdge(adjVirt->theEdge());
			if (eCopy == nullptr) continue;
			if (adjVirt == adj) {
				lastAdj[vT] = adj;
				continue;
			}

			const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge()));

			adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ?
				eCopy->adjSource() : eCopy->adjTarget();

			setPosInEmbedding(adjEdges,currentCopy,lastAdj,current,
				STwin, adjCopy);
		}

	} else if (lastAdj[vT] != nullptr && lastAdj[vT] != adj) {
		adjEntry adjVirt = lastAdj[vT];
		edge eCopy = S.twinEdge(adjVirt->theEdge());

		const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge()));

		adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ?
			eCopy->adjSource() : eCopy->adjTarget();

		setPosInEmbedding(adjEdges,currentCopy,lastAdj,current,
			STwin, adjCopy);

		lastAdj[vT] = nullptr;
	}

}
Example #2
0
SkeletonFrame* SkeletonTracker::NewSkeleton(XnUserID uid) {
	SkeletonFrame skeleton(uid);
	UserSkeletonMap::iterator it;
	// if there's already a skeleton with this UID, bail out
	if (this->UserExists(uid)) {
		return NULL;
	}
	this->QueueAction("add", uid);
	it = this->skeletons.insert(std::pair<XnUserID,SkeletonFrame>(uid, skeleton)).first;
	return &it->second;
}
Example #3
0
//
// embed original graph according to embedding of skeletons
//
// The procedure also handles the case when some (real or virtual)
// edges are reversed (used in upward-planarity algorithms)
void PlanarSPQRTree::embed(Graph &G)
{
	OGDF_ASSERT(&G == &originalGraph());

	const Skeleton &S = skeleton(rootNode());
	const Graph &M = S.getGraph();

	for (node v : M.nodes)
	{
		node vOrig = S.original(v);
		SListPure<adjEntry> adjEdges;

		for (adjEntry adj : v->adjEdges) {
			edge e = adj->theEdge();
			edge eOrig = S.realEdge(e);

			if (eOrig != nullptr) {
				adjEntry adjOrig = (vOrig == eOrig->source()) ?
					eOrig->adjSource() : eOrig->adjTarget();
				OGDF_ASSERT(adjOrig->theNode() == S.original(v));
				adjEdges.pushBack(adjOrig);

			} else {
				node wT    = S.twinTreeNode(e);
				edge eTwin = S.twinEdge(e);
				expandVirtualEmbed(wT,
					(vOrig == skeleton(wT).original(eTwin->source())) ?
					eTwin->adjSource() : eTwin->adjTarget(),
					adjEdges);
			}
		}

		G.sort(vOrig,adjEdges);
	}

	edge e;
	forall_adj_edges(e,rootNode()) {
		node wT = e->target();
		if (wT != rootNode())
			createInnerVerticesEmbed(G, wT);
	}
Example #4
0
void LineFinder::createSkeleton(int threshold)
{
    // the image has to be grayscale
    if (Play::getInstance()->getFinder()->getImage().channels() != 1)
    {
        cv::cvtColor(Play::getInstance()->getFinder()->getImage(), Play::getInstance()->getFinder()->getImage(), cv::COLOR_BGR2GRAY);
    }
    
    // we need to enhance the lighting before we can threshold the image
    cv::equalizeHist(Play::getInstance()->getFinder()->getImage(), Play::getInstance()->getFinder()->getImage());
    // a binary image is needed
    cv::threshold(Play::getInstance()->getFinder()->getImage(), Play::getInstance()->getFinder()->getImage(), threshold, 255, cv::THRESH_BINARY_INV);
    
    // the resulting skeleton
    cv::Mat skeleton(Play::getInstance()->getFinder()->getImage().size(), CV_8UC1, cv::Scalar(0,0,0));
    // needed if in-place processing is not possible
    cv::Mat temp(Play::getInstance()->getFinder()->getImage().size(), CV_8UC1);
    // eroded image is saved here
    cv::Mat eroded;
    // needed for morphological transforms (erosion, dilation)
    cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(9,9));
    
    int i = 0;
    while(i != 20)
    {
        // eroding + dilating = opening
        cv::erode(Play::getInstance()->getFinder()->getImage(), eroded, element);
        cv::dilate(eroded, temp, element);
        cv::subtract(Play::getInstance()->getFinder()->getImage(), temp, temp);
        cv::bitwise_or(skeleton, temp, skeleton);
        eroded.copyTo(Play::getInstance()->getFinder()->getImage());
        
        //done = (cv::countNonZero(image) == 0);
        ++i;
    }

    Play::getInstance()->getFinder()->setImage(skeleton);
}
Example #5
0
void PlanarSPQRTree::adoptEmbedding()
{
	OGDF_ASSERT_IF(dlExtendedChecking, originalGraph().representsCombEmbedding());

	// ordered list of adjacency entries (for one original node) in all
	// skeletons (where this node occurs)
	NodeArray<SListPure<adjEntry> > adjEdges(tree());
	// copy in skeleton of current original node
	NodeArray<node> currentCopy(tree(),nullptr);
	NodeArray<adjEntry> lastAdj(tree(),nullptr);
	SListPure<node> current; // currently processed nodes

	for (node vOrig : originalGraph().nodes)
	{
		for(adjEntry adjOrig : vOrig->adjEdges)
		{
			edge            eOrig = adjOrig->theEdge();
			const Skeleton &S     = skeletonOfReal(eOrig);
			edge            eCopy = copyOfReal(eOrig);

			adjEntry adjCopy = (S.original(eCopy->source()) == vOrig) ?
				eCopy->adjSource() : eCopy->adjTarget();

			setPosInEmbedding(adjEdges,currentCopy,lastAdj,current,S,adjCopy);
		}

		for(node vT : current) {
			skeleton(vT).getGraph().sort(currentCopy[vT],adjEdges[vT]);

			adjEdges[vT].clear();
			currentCopy[vT] = nullptr;
		}

		current.clear();
	}
}
Example #6
0
void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* filename, const char *sourcefile, size_t size)
{
	if (sourcefile == NULL)
	{
		throw Ogre::InsufficientData(FormatString("Failed to load '%s/%s'", groupname, filename).getData());
	}

	std::shared_ptr<StdMeshLoader::StdMeshXML> skeleton(new StdMeshLoader::StdMeshXML(filename, sourcefile));

	TiXmlElement* skeleton_elem = skeleton->RequireFirstChild(NULL, "skeleton");
	TiXmlElement* bones_elem = skeleton->RequireFirstChild(skeleton_elem, "bones");

	// Read bones. Don't insert into Master bone table yet, as the master bone
	// table is sorted hierarchically, and we will read the hierarchy only
	// afterwards.
	std::vector<StdMeshBone*> bones;
	for (TiXmlElement* bone_elem = bones_elem->FirstChildElement("bone"); bone_elem != NULL; bone_elem = bone_elem->NextSiblingElement("bone"))
	{
		StdMeshBone* bone = new StdMeshBone;
		bones.push_back(bone);

		bone->ID = skeleton->RequireIntAttribute(bone_elem, "id");
		bone->Name = skeleton->RequireStrAttribute(bone_elem, "name");
		// TODO: Make sure ID and name are unique

		bone->Parent = NULL;
		// Index of bone will be set when building Master Bone Table later

		TiXmlElement* position_elem = skeleton->RequireFirstChild(bone_elem, "position");
		TiXmlElement* rotation_elem = skeleton->RequireFirstChild(bone_elem, "rotation");
		TiXmlElement* axis_elem = skeleton->RequireFirstChild(rotation_elem, "axis");

		StdMeshVector d, r;
		d.x = skeleton->RequireFloatAttribute(position_elem, "x");
		d.y = skeleton->RequireFloatAttribute(position_elem, "y");
		d.z = skeleton->RequireFloatAttribute(position_elem, "z");
		float angle = skeleton->RequireFloatAttribute(rotation_elem, "angle");
		r.x = skeleton->RequireFloatAttribute(axis_elem, "x");
		r.y = skeleton->RequireFloatAttribute(axis_elem, "y");
		r.z = skeleton->RequireFloatAttribute(axis_elem, "z");

		bone->Transformation.scale = StdMeshVector::UnitScale();
		bone->Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r);
		bone->Transformation.translate = d;

		// We need this later for applying animations, and attaching meshes, therefore cache it here
		bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation);
	}

	// Bone hierarchy
	TiXmlElement* bonehierarchy_elem = skeleton->RequireFirstChild(skeleton_elem, "bonehierarchy");
	for (TiXmlElement* boneparent_elem = bonehierarchy_elem->FirstChildElement("boneparent"); boneparent_elem != NULL; boneparent_elem = boneparent_elem->NextSiblingElement("boneparent"))
	{
		const char* child_name = skeleton->RequireStrAttribute(boneparent_elem, "bone");
		const char* parent_name = skeleton->RequireStrAttribute(boneparent_elem, "parent");

		// Lookup the two bones
		StdMeshBone* child = NULL;
		StdMeshBone* parent = NULL;
		for (unsigned int i = 0; i < bones.size() && (!child || !parent); ++i)
		{
			if (!child && bones[i]->Name == child_name)
				child = bones[i];
			if (!parent && bones[i]->Name == parent_name)
				parent = bones[i];
		}

		if (!child) skeleton->Error(FormatString("There is no such bone with name '%s'", child_name), boneparent_elem);
		if (!parent) skeleton->Error(FormatString("There is no such bone with name '%s'", parent_name), boneparent_elem);

		child->Parent = parent;
		parent->Children.push_back(child);
	}

	std::shared_ptr<StdMeshSkeleton> Skeleton(new StdMeshSkeleton);

	// Fill master bone table in hierarchical order:
	for (unsigned int i = 0; i < bones.size(); ++i)
		if (bones[i]->Parent == NULL)
			Skeleton->AddMasterBone(bones[i]);

	// Load Animations
	TiXmlElement* animations_elem = skeleton_elem->FirstChildElement("animations");
	if (animations_elem)
	{
		for (TiXmlElement* animation_elem = animations_elem->FirstChildElement("animation"); animation_elem != NULL; animation_elem = animation_elem->NextSiblingElement("animation"))
		{
			StdCopyStrBuf name(skeleton->RequireStrAttribute(animation_elem, "name"));
			if (Skeleton->Animations.find(name) != Skeleton->Animations.end())
				skeleton->Error(FormatString("There is already an animation with name '%s'", name.getData()), animation_elem);

			StdMeshAnimation& animation = Skeleton->Animations.insert(std::make_pair(name, StdMeshAnimation())).first->second;
			animation.Name = name;
			animation.Length = skeleton->RequireFloatAttribute(animation_elem, "length");
			animation.Tracks.resize(Skeleton->GetNumBones());
			animation.OriginSkeleton = &(*Skeleton);

			TiXmlElement* tracks_elem = skeleton->RequireFirstChild(animation_elem, "tracks");
			for (TiXmlElement* track_elem = tracks_elem->FirstChildElement("track"); track_elem != NULL; track_elem = track_elem->NextSiblingElement("track"))
			{
				const char* bone_name = skeleton->RequireStrAttribute(track_elem, "bone");
				StdMeshBone* bone = NULL;
				for (unsigned int i = 0; !bone && i < Skeleton->GetNumBones(); ++i)
					if (Skeleton->Bones[i]->Name == bone_name)
						bone = Skeleton->Bones[i];
				if (!bone) skeleton->Error(FormatString("There is no such bone with name '%s'", bone_name), track_elem);

				if (animation.Tracks[bone->Index] != NULL) skeleton->Error(FormatString("There is already a track for bone '%s' in animation '%s'", bone_name, animation.Name.getData()), track_elem);

				StdMeshTrack* track = new StdMeshTrack;
				animation.Tracks[bone->Index] = track;

				TiXmlElement* keyframes_elem = skeleton->RequireFirstChild(track_elem, "keyframes");
				for (TiXmlElement* keyframe_elem = keyframes_elem->FirstChildElement("keyframe"); keyframe_elem != NULL; keyframe_elem = keyframe_elem->NextSiblingElement("keyframe"))
				{
					float time = skeleton->RequireFloatAttribute(keyframe_elem, "time");
					StdMeshKeyFrame& frame = track->Frames[time];

					TiXmlElement* translate_elem = keyframe_elem->FirstChildElement("translate");
					TiXmlElement* rotate_elem = keyframe_elem->FirstChildElement("rotate");
					TiXmlElement* scale_elem = keyframe_elem->FirstChildElement("scale");

					StdMeshVector d, s, r;
					d.x = d.y = d.z = 0.0f;
					s = StdMeshVector::UnitScale();
					r.x = r.y = 0.0f; r.z = 1.0f;
					float angle = 0.0f;

					if (translate_elem)
					{
						d.x = skeleton->RequireFloatAttribute(translate_elem, "x");
						d.y = skeleton->RequireFloatAttribute(translate_elem, "y");
						d.z = skeleton->RequireFloatAttribute(translate_elem, "z");
					}

					if (rotate_elem)
					{
						TiXmlElement* axis_elem = skeleton->RequireFirstChild(rotate_elem, "axis");
						angle = skeleton->RequireFloatAttribute(rotate_elem, "angle");
						r.x = skeleton->RequireFloatAttribute(axis_elem, "x");
						r.y = skeleton->RequireFloatAttribute(axis_elem, "y");
						r.z = skeleton->RequireFloatAttribute(axis_elem, "z");
					}

					if (scale_elem)
					{
						s.x = skeleton->RequireFloatAttribute(scale_elem, "x");
						s.y = skeleton->RequireFloatAttribute(scale_elem, "y");
						s.z = skeleton->RequireFloatAttribute(scale_elem, "z");
					}

					frame.Transformation.scale = s;
					frame.Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r);
					frame.Transformation.translate = bone->InverseTransformation.rotate * (bone->InverseTransformation.scale * d);
					frame.Transformation = OgreToClonk::TransformTransformation(frame.Transformation);
				}
			}
		}
	}

	// is there even any xml file that we load from?
	// it looks like this could never work: if the mesh has no skeleton, then the code below will fail because of a null pointer...

	// Apply parent transformation to each bone transformation. We need to
	// do this late since animation keyframe computation needs the bone
	// transformations, not bone+parent.
	for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i)
	{
		// Apply parent transformation
		if (Skeleton->Bones[i]->Parent)
			Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);
		else
			Skeleton->Bones[i]->Transformation = OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);

		// Update inverse
		Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation);
	}

	StoreSkeleton(groupname, filename, Skeleton);
}
void CmpCharacterModelRender::update_animation(int milliseconds)
{
	// Decide which animation should be playing, and update it.
	ICmpAnimChooser_Ptr cmpAnimChooser = m_objectManager->get_component(m_objectID, cmpAnimChooser);	assert(cmpAnimChooser);
	m_animController->request_animation(cmpAnimChooser->choose_animation());
	m_animController->update(milliseconds);

	// Clear any existing pose modifiers.
	m_animController->clear_pose_modifiers();

	// Determine the animation extension of any carried item in order to determine which bones need to be inclined.
	std::string animExtension = "";		// the explicit initialisation is to make it clear that "" is the default

	ICmpInventory_Ptr cmpInventory = m_objectManager->get_component(m_objectID, cmpInventory);	assert(cmpInventory);
	ObjectID activeItem = cmpInventory->active_item();
	if(activeItem.valid())
	{
		ICmpOwnable_Ptr cmpItemOwnable = m_objectManager->get_component(activeItem, cmpItemOwnable);	assert(cmpItemOwnable);
		animExtension = cmpItemOwnable->anim_extension();
	}

	// Calculate the inclination of the object's coordinate system and apply pose modifiers to the relevant bones.
	BoneModifierMap::const_iterator it = m_inclineBones.find(animExtension);
	if(it != m_inclineBones.end())
	{
		ICmpOrientation_Ptr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation);
		const Vector3d& n = cmpOrientation->nuv_axes()->n();

		double sinInclination = n.z / n.length();
		if(sinInclination < -1) sinInclination = -1;
		if(sinInclination > 1) sinInclination = 1;
		double inclination = asin(sinInclination);

		for(std::map<std::string,Vector3d>::const_iterator jt=it->second.begin(), jend=it->second.end(); jt!=jend; ++jt)
		{
			m_animController->set_pose_modifier(jt->first, PoseModifier(jt->second, -inclination));
		}
	}

	// Configure the pose.
	m_modelPose = model()->configure_pose(m_animController);

	// Update the animation for the active item (if any), e.g. the weapon being carried.
	if(activeItem.valid())
	{
		ICmpOrientation_CPtr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation);
		ICmpPosition_CPtr cmpPosition = m_objectManager->get_component(m_objectID, cmpPosition);

		const Vector3d& p = cmpPosition->position();
		const Vector3d& n = cmpOrientation->nuv_axes()->n();
		const Vector3d& u = cmpOrientation->nuv_axes()->u();
		const Vector3d& v = cmpOrientation->nuv_axes()->v();

		RBTMatrix_CPtr modelMatrix = construct_model_matrix(p, n, u, v);

		ICmpOwnable_Ptr cmpItemOwnable = m_objectManager->get_component(activeItem, cmpItemOwnable);	assert(cmpItemOwnable);
		ICmpBasicModelRender_Ptr cmpItemRender = m_objectManager->get_component(activeItem, cmpItemRender);
		if(cmpItemRender)
		{
			cmpItemRender->update_child_animation(milliseconds, skeleton()->bone_hierarchy(), cmpItemOwnable->attach_point(), modelMatrix);
		}
	}
}
Example #8
0
void WldModel::readAnimatedModel(Frag11* f11)
{
    WLD* wld            = m_wld;
    PFS* pfs            = getPFS();
    ConvSkeleton& skele = skeleton();
    
    Frag10* f10 = (Frag10*)wld->getFrag(f11->ref);
    
    if (!f10 || f10->type() != 0x10 || f10->boneCount() == 0)
        throw 3; //fixme
    
    int boneCount           = f10->boneCount();
    Frag10Bone* rootBone    = f10->boneList();
    Frag10Bone* binBone     = rootBone;
    
    skele.init((uint32_t)boneCount);
    
    // Read and convert bones
    for (int i = 0; i < boneCount; i++)
    {
        Frag13* f13 = (Frag13*)wld->getFrag(binBone->refA);
        
        if (!f13 || f13->type() != 0x13)
            throw 4; //fixme
        
        Frag12* f12 = (Frag12*)wld->getFrag(f13->ref);
        
        if (!f12 || f12->type() != 0x12)
            throw 5; //fixme
        
        Vec3 pos;
        Quaternion rot;
        
        f12->entry[0].getPosRot(pos, rot);
        skele.setBone((uint32_t)i, pos, rot);
        
        const char* name = wld->getFragName(f13);
        skele.addBoneNameToIndex(name, (uint32_t)i);
        
        if (strstr(name, "_point_track"))
        {
            AttachPoint::Type attach = AttachPoint::Type::NONE;
            const char* p = name + 3;
            
            switch (*p)
            {
            case 't':
                attach = AttachPoint::Type::RightHand;
                break;
            case 'l':
                attach = AttachPoint::Type::LeftHand;
                break;
            case 'h':
                if (strstr(p, "head"))
                    attach = AttachPoint::Type::Camera;
                break;
            case 's':
                if (strstr(p, "shield"))
                    attach = AttachPoint::Type::Shield;
                break;
            }
            
            skele.setAttachPointType((uint32_t)i, attach);
        }
        
        binBone = binBone->next();
    }
    
    // Read bone hierarchy
    binBone = rootBone;
    for (int i = 0; i < boneCount; i++)
    {
        if (binBone->size > 0)
        {
            int* index = binBone->indexList();
            
            for (int j = 0; j < binBone->size; j++)
            {
                skele.addChild((uint32_t)i, (uint32_t)index[j]);
            }
        }
        
        binBone = binBone->next();
    }
    
    skele.buildIndexMap();
    
    // Read animations
    struct Frag12PlusBoneIndex
    {
        Frag12*     f12;
        uint32_t    frameRate;
        uint32_t    boneIndex;
    };
    
    std::unordered_map<int, std::vector<Frag12PlusBoneIndex>> animsById;
    
    for (Fragment* frag : wld->getFragsByType(0x13))
    {
        Frag13* f13 = (Frag13*)frag;
        
        uint32_t index;
        const char* name = wld->getFragName(frag);
        
        if (!skele.getIndexByName(name + 3, index))
            continue;
        
        int animId  = getAnimId(name);
        Frag12* f12 = (Frag12*)wld->getFrag(f13->ref);
        
        if (!f12 || f12->type() != 0x12)
            continue;
        
        Frag12PlusBoneIndex fbi;
        
        fbi.f12             = f12;
        fbi.frameRate       = f13->getFrameRate();
        fbi.boneIndex       = index;
        
        animsById[animId].push_back(fbi);
    }
    
    // Convert anims
    for (auto& p : animsById)
    {
        uint32_t frameCount = 0;
        uint32_t frameRate  = 0;
        
        for (Frag12PlusBoneIndex& fbi : p.second)
        {
            Frag12* f12 = fbi.f12;
            
            if (f12->count > frameCount)
                frameCount = f12->count;
            
            if (frameRate == 0 && fbi.frameRate)
                frameRate = fbi.frameRate;
        }
        
        printf("anim %i frameRate: %u\n", p.first, frameRate);
        Animation* anim = Animation::create(frameCount, frameRate, boneCount);
        
        for (Frag12PlusBoneIndex& fbi : p.second)
        {
            anim->addFrames(fbi.boneIndex, fbi.f12);
        }
        
        addAnimation(p.first, anim);
    }
    
    // VertexBuffers and Head models
    int modelCount  = 0;
    int* refs       = f10->refList(modelCount);
    
    struct HeadId
    {
        uint32_t    id;
        WldModel*   head;
    };
    
    std::vector<HeadId> heads;
    
    for (int i = 0; i < modelCount; i++)
    {
        Frag2d* f2d = (Frag2d*)wld->getFrag(refs[i]);
        
        if (!f2d || f2d->type() != 0x2d)
            continue;
        
        Frag36* f36 = (Frag36*)wld->getFrag(f2d->ref);
        
        if (!f36 || f36->type() != 0x36)
            continue;
        
        const char* name = wld->getFragName(f36);
        printf("%s\n", name);
        
        WldModel* model;
        
        if (name[3] == 'h' && name[4] == 'e')
        {
            model = new WldModel(pfs, wld);
            
            HeadId h;
            h.id    = ::strtol(name + 5, nullptr, 10);
            h.head  = model;
            heads.push_back(h);
        }
        else
        {
            model = this;
        }
        
        model->readMaterials(f36);
        model->readMesh(f36, false, &skele);
    }
    
    std::sort(heads.begin(), heads.end(), [](const HeadId& a, const HeadId& b) { return a.id < b.id; });
    
    for (auto& h : heads)
    {
        addHeadModel(h.head);
    }
}
Example #9
0
bool CalSaver::saveXmlCoreSkeleton(const std::string& strFilename, CalCoreSkeleton *pCoreSkeleton)
{
  std::stringstream str;

  vsxTiXmlDocument doc(strFilename);  


  vsxTiXmlElement skeleton("SKELETON");
  //skeleton.SetAttribute("MAGIC",Cal::SKELETON_XMLFILE_MAGIC);
  skeleton.SetAttribute("VERSION",Cal::LIBRARY_VERSION);

  skeleton.SetAttribute("NUMBONES",pCoreSkeleton->getVectorCoreBone().size());
  


  int boneId;
  for(boneId = 0; boneId < (int)pCoreSkeleton->getVectorCoreBone().size(); ++boneId)
  {
	  CalCoreBone* pCoreBone=pCoreSkeleton->getCoreBone(boneId);

	  vsxTiXmlElement bone("BONE");	  
	  bone.SetAttribute("ID",boneId);
	  bone.SetAttribute("NAME",pCoreBone->getName());
	  bone.SetAttribute("NUMCHILDS",pCoreBone->getListChildId().size());

	  vsxTiXmlElement translation("TRANSLATION");
	  const CalVector& translationVector = pCoreBone->getTranslation();
      

      str.str("");
      str << translationVector.x << " " 
    	  << translationVector.y << " "
	      << translationVector.z;
  
      vsxTiXmlText translationdata(str.str());  

      translation.InsertEndChild(translationdata);
      bone.InsertEndChild(translation);


	  vsxTiXmlElement rotation("ROTATION");
	  const CalQuaternion& rotationQuad = pCoreBone->getRotation();  
      

      str.str("");
      str << rotationQuad.x << " " 
    	  << rotationQuad.y << " "
		  << rotationQuad.z << " "
	      << rotationQuad.w;
  
      vsxTiXmlText rotationdata(str.str());
      rotation.InsertEndChild(rotationdata);
      bone.InsertEndChild(rotation);


	  vsxTiXmlElement localtranslation("LOCALTRANSLATION");
	  const CalVector& localtranslationVector = pCoreBone->getTranslationBoneSpace();      

      str.str("");
      str << localtranslationVector.x << " " 
    	  << localtranslationVector.y << " "
	      << localtranslationVector.z;
  
      vsxTiXmlText localtranslationdata(str.str()); 

      localtranslation.InsertEndChild(localtranslationdata);
      bone.InsertEndChild(localtranslation);


	  vsxTiXmlElement localrotation("LOCALROTATION");
	  const CalQuaternion& localrotationQuad = pCoreBone->getRotationBoneSpace();        

      str.str("");
      str << localrotationQuad.x << " " 
    	  << localrotationQuad.y << " "
		  << localrotationQuad.z << " "
	      << localrotationQuad.w;
  
      vsxTiXmlText localrotationdata(str.str());
      localrotation.InsertEndChild(localrotationdata);
      bone.InsertEndChild(localrotation);


	  vsxTiXmlElement parent("PARENTID");
	  str.str("");
      str << pCoreBone->getParentId();
	  vsxTiXmlText parentid(str.str());
	  parent.InsertEndChild(parentid);
      bone.InsertEndChild(parent);


	  // get children list
      std::list<int>& listChildId = pCoreBone->getListChildId();


	  // write all children ids
      std::list<int>::iterator iteratorChildId;
      for(iteratorChildId = listChildId.begin(); iteratorChildId != listChildId.end(); ++iteratorChildId)
	  {
		  vsxTiXmlElement child("CHILDID");
		  str.str("");
		  //int id=*iteratorChildId;
          str << *iteratorChildId;
	      vsxTiXmlText childid(str.str());
		  child.InsertEndChild(childid);
          bone.InsertEndChild(child);
	  }
	  skeleton.InsertEndChild(bone);

  }
  doc.InsertEndChild(skeleton);
  
  if(!doc.SaveFile())
  {
	CalError::setLastError(CalError::FILE_WRITING_FAILED, __FILE__, __LINE__, strFilename);
    return false;
  }
  return true;
}