Developer Documentation
FileSkeleton.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 #include "FileSkeleton.hh"
43 
45 
46 #include <OpenMesh/Core/IO/IOManager.hh>
47 
48 
49 
51 }
52 
54  return QString( "Skeleton files ( *.skl )" );
55 };
56 
58  return QString( "Skeleton files ( *.skl )" );
59 };
60 
62  DataType type = DATA_SKELETON;
63  return type;
64 }
65 
66 template<typename Skeleton>
67 bool FileSKLPlugin::LoadSkeleton(Skeleton *_pSkeleton, QString _filename)
68 {
72 
73  unsigned int nJoints = 0;
74 
75  std::ifstream in(_filename.toStdString().c_str(), std::ofstream::in);
76 
77  // read number of joints
78  in >> nJoints;
79 
80  Pose *ref = _pSkeleton->referencePose();
81  // remember parent joints
82  std::map<unsigned int, Joint*> parents;
83 
84  std::map<unsigned int, unsigned int> jointMap;
85 
86  for(unsigned int i = 0; i < nJoints; ++i)
87  {
88  // id not stored in skeleton; the read order is increasing for joints
89  unsigned int id;
90 
91  // read joint id
92  in >> id;
93 
94  // read its matrix
95  Matrix mat;
96  mat.identity();
97  for(int y = 0; y < 3; ++y)
98  for(int x = 0; x < 3; ++x)
99  in >> mat(y, x);
100  for(int y = 0; y < 3; ++y)
101  in >> mat(y, 3);
102 
103  // try to find the parent joint
104  Joint *pParent = 0;
105  if(parents.find(id) != parents.end())
106  pParent = parents[id];
107 
108  // setup the new joint
109  Joint *pJoint = new Joint(pParent);
110  _pSkeleton->addJoint(pParent, pJoint);
111 
112  jointMap[ id ] = pJoint->id();
113 
114  // save the joints position
115  ref->setGlobalMatrix(jointMap[ id ], mat);
116 
117  // how many child nodes
118  unsigned int nChildren;
119  in >> nChildren;
120 
121  for(unsigned int j = 0; j < nChildren; ++j)
122  {
123  // remember to attach this child joint once its being load
124  unsigned int idChild;
125  in >> idChild;
126 
127  parents[idChild] = pJoint;
128  }
129  }
130 
131  unsigned int num_anim = 0;
132  while(in.good()) {
133 
134  num_anim++;
135 
136  // Test whether animation name is provided
137  std::string identifier;
138  in >> identifier;
139  std::string animationName = (QString("Animation") + QString::number(num_anim)).toStdString();
140 
141  //read animation
142  unsigned int frameCount = 0;
143 
144 
145  if(identifier == "animation") {
146  std::getline(in, animationName);
147  // Trim string
148  animationName = QString(animationName.c_str()).trimmed().toStdString();
149 
150  in >> frameCount;
151  } else {
152 
153  std::istringstream tmp(identifier);
154  tmp >> frameCount;
155 
156  }
157 
158  if ( frameCount > 0 ){
159 
160  FrameAnimationT<ACG::Vec3d>* animation = new FrameAnimationT<ACG::Vec3d>(_pSkeleton, frameCount);
161  AnimationHandle animHandle = _pSkeleton->addAnimation(animationName, animation);
162 
163  for (unsigned int k = 0; k < frameCount; k++){
164 
165  animHandle.setFrame(k);
166  typename Skeleton::Pose* pose = _pSkeleton->pose( animHandle );
167 
168  for(unsigned int i = 0; i < nJoints; ++i)
169  {
170  unsigned int id; // id not stored in skeleton; the read order is increasing for joints
171 
172  // read joint id
173  in >> id;
174 
175  // read its matrix
176  Matrix mat;
177  mat.identity();
178  for(int y = 0; y < 3; ++y)
179  for(int x = 0; x < 3; ++x)
180  in >> mat(y, x);
181  for(int y = 0; y < 3; ++y)
182  in >> mat(y, 3);
183 
184  //set matrix
185  pose->setGlobalMatrix(jointMap[ id ], mat);
186  }
187  }
188  }
189  }
190 
191  in.close();
192 
193  return true;
194 }
195 
196 int FileSKLPlugin::loadObject(QString _filename)
197 {
198  int id = -1;
199  emit addEmptyObject(DATA_SKELETON, id);
200 
201  BaseObjectData *obj(0);
202  if(PluginFunctions::getObject(id, obj))
203  {
205 
206  LoadSkeleton(skel->skeleton(), _filename);
207 
208  //general stuff
209  obj->source( PluginFunctions::objectCount() > 4 );
210  obj->setFromFileName(_filename);
211  obj->setName(obj->filename());
212  emit updatedObject( obj->id(), UPDATE_ALL );
213  emit openedFile( obj->id() );
214  } else {
215  emit log(LOGERR,tr("Unable to add empty skeleton"));
216  }
217 
218 
219  return id;
220 };
221 
222 template<typename Skeleton>
223 bool FileSKLPlugin::SaveSkeleton(Skeleton *_pSkeleton, QString _filename)
224 {
225  typedef JointT<typename Skeleton::Point> Joint;
226  typedef PoseT<typename Skeleton::Point> Pose;
228 
229  std::ofstream out(_filename.toStdString().c_str(), std::ofstream::out);
230 
231  // write the number of joints
232  out << _pSkeleton->jointCount() << std::endl;
233 
234  Pose *ref = _pSkeleton->referencePose();
235  // write all the joints
236  for (typename Skeleton::Iterator it = _pSkeleton->begin(); it != _pSkeleton->end(); ++it ){
237 
238  unsigned int i = (*it)->id();
239  Joint *pJoint = *it;
240 
241  // write this joints id
242  out << pJoint->id() << " ";
243 
244  // write its position
245  const Matrix &mat = ref->globalMatrix(i);
246  for(int y = 0; y < 3; ++y)
247  for(int x = 0; x < 3; ++x)
248  out << mat(y, x) << " ";
249  for(int y = 0; y < 3; ++y)
250  out << mat(y, 3) << " ";
251 
252  // write this joints number of children
253  out << pJoint->size() << " ";
254 
255  // write the children
256  for(unsigned int j = 0; j < pJoint->size(); ++j)
257  out << pJoint->child(j)->id() << " ";
258 
259  out << std::endl;
260  }
261 
262  // now store animations
263  AnimationT<ACG::Vec3d>* animation = 0;
264 
265  for (unsigned int i = 0; i < _pSkeleton->animationCount(); i++) {
266 
267  animation = _pSkeleton->animation(AnimationHandle(i, 0));
268 
269  if (animation != 0) {
270 
271  std::string name = animation->name();
272 
273  out << "animation " << name << std::endl;
274 
275  out << animation->frameCount() << std::endl;
276 
277  AnimationHandle animHandle = _pSkeleton->animationHandle(name);
278 
279  // every frame of that animation
280  for (unsigned int k = 0; k < animation->frameCount(); ++k) {
281 
282  animHandle.setFrame(k);
283  typename Skeleton::Pose* pose = _pSkeleton->pose(animHandle);
284 
285  for (typename Skeleton::Iterator it = _pSkeleton->begin(); it != _pSkeleton->end(); ++it) {
286 
287  unsigned int i = (*it)->id();
288  Joint *pJoint = *it;
289 
290  // write this joints id
291  out << pJoint->id() << " ";
292 
293  // write its position
294  const Matrix &mat = pose->globalMatrix(i);
295  for (int y = 0; y < 3; ++y)
296  for (int x = 0; x < 3; ++x)
297  out << mat(y, x) << " ";
298  for (int y = 0; y < 3; ++y)
299  out << mat(y, 3) << " ";
300  }
301 
302  out << std::endl;
303  }
304  } else {
305  out << "0" << std::endl;
306  }
307  }
308 
309  out.close();
310  return !out.fail();
311 }
312 
313 bool FileSKLPlugin::saveObject(int _id, QString _filename)
314 {
315  BaseObjectData *obj(0);
316  if(PluginFunctions::getObject(_id, obj))
317  {
319  if(skel)
320  {
321  obj->setFromFileName(_filename);
322  obj->setName(obj->filename());
323  SaveSkeleton(skel->skeleton(), _filename);
324  }
325  } else {
326  emit log(LOGERR, tr("saveObject : cannot get object id %1 for save name %2").arg(_id).arg(_filename) );
327  return false;
328  }
329 
330  return true;
331 }
332 
333 void FileSKLPlugin::loadIniFile( INIFile& _ini ,int _id ) {
334  BaseObjectData* baseObject;
335  if ( !PluginFunctions::getObject(_id,baseObject) ) {
336  emit log(LOGERR,"Cannot find object for id " + QString::number(_id) + " in saveFile" );
337  return;
338  }
339 
340  if ( baseObject->materialNode() != 0 ) {
341  ACG::Vec4f col(0.0,0.0,0.0,0.0);
342 
343  if ( _ini.get_entryVecf( col, baseObject->name() , "BaseColor" ) )
344  baseObject->materialNode()->set_base_color(col);
345  }
346 
347 }
348 
349 void FileSKLPlugin::saveIniFile( INIFile& _ini ,int _id) {
350  BaseObjectData* baseObject;
351  if ( !PluginFunctions::getObject(_id,baseObject) ) {
352  emit log(LOGERR,"Cannot find object for id " + QString::number(_id) + " in saveFile" );
353  return;
354  }
355 
356 
357  if ( baseObject->materialNode() != 0 ) {
358  _ini.add_entryVec( baseObject->name() ,
359  "BaseColor" ,
360  baseObject->materialNode()->base_color() );
361  }
362 }
363 
364 
365 
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
bool source()
Definition: BaseObject.cc:291
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
Definition: PoseT_impl.hh:211
virtual void setName(QString _name) override
path to the file from which the object is loaded ( defaults to "." )
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool get_entryVecf(VectorT &_val, const QString &_section, const QString &_key) const
Get a Vec_n_i (int)
QString name()
Return a name for the plugin.
Definition: FileSkeleton.hh:91
size_t jointCount()
Returns the number of joints.
int objectCount()
Get the number of available objects.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
#define DATA_SKELETON
Definition: Skeleton.hh:64
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:58
Pose * pose(unsigned int _iFrame)
Returns a pointer to the pose stored in the given frame.
Predefined datatypes.
Definition: DataTypes.hh:83
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
int id() const
Definition: BaseObject.cc:190
void loadIniFile(INIFile &_ini, int _id)
Load per object settings.
void setFrame(size_t _iFrame)
Sets the current animation frame (not failsafe)
void initializePlugin()
Initialize Plugin.
Definition: FileSkeleton.cc:50
QString getSaveFilters()
Definition: FileSkeleton.cc:57
Represents a single joint in the skeleton.
Definition: JointT.hh:60
Pose * referencePose()
Returns a pointer to the reference pose.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
QString name() const
return the name of the object. The name defaults to NONAME if unset.
Definition: BaseObject.cc:730
void saveIniFile(INIFile &_ini, int _id)
Save per object settings.
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
const Vec4f & base_color() const
get the base color ( same as emission() )
QString getLoadFilters()
Definition: FileSkeleton.cc:53
Iterator class for the skeleton.
Definition: SkeletonT.hh:82
MaterialNode * materialNode()
get a pointer to the materialnode
void add_entryVec(const QString &_section, const QString &_key, const VectorT &_value)
Addition of a Vec_n_something.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Class for the handling of simple configuration files.
Definition: INIFile.hh:99
size_t animationCount()
Returns the number of animations stored in this skeleton.
void set_base_color(const Vec4f &_c)
set the base color ( Same as set_emission(const Vec4f& _c) )
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Definition: FileSkeleton.cc:61
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Definition: PoseT_impl.hh:193
Skeleton * skeleton()
Returns a pointer to the skeleton.
A handle used to refer to an animation or to a specific frame in an animation.
void setFromFileName(const QString &_filename)
Definition: BaseObject.cc:716