root/OpenSceneGraph/trunk/src/osgPlugins/bvh/ReaderWriterBVH.cpp @ 9371

Revision 9371, 13.8 kB (checked in by robert, 5 years ago)

Build fixes for when the implict ref_ptr<> cast is not enabled

RevLine 
[9304]1#include <osg/Notify>
2#include <osg/Geometry>
3#include <osg/ShapeDrawable>
4
5#include <osgDB/FileNameUtils>
6#include <osgDB/FileUtils>
7#include <osgDB/Registry>
8
9#include <osgAnimation/Bone>
10#include <osgAnimation/Skeleton>
[9370]11#include <osgAnimation/BasicAnimationManager>
[9304]12
13class BvhMotionBuilder : public osg::Referenced
14{
15public:
16    typedef std::pair<osg::ref_ptr<osgAnimation::Bone>, int> JointNode;
17    typedef std::vector<JointNode> JointList;
18
19    BvhMotionBuilder() : _drawingFlag(0) {}
20    virtual ~BvhMotionBuilder() {}
21
22    static BvhMotionBuilder* instance()
23    {
24        static osg::ref_ptr<BvhMotionBuilder> s_library = new BvhMotionBuilder;
25        return s_library.get();
26    }
27
28    void buildHierarchy( osgDB::Input& fr, int level, osgAnimation::Bone* parent )
29    {
30        bool isRecognized = false;
31        if ( !parent ) return;
32
33        if ( fr.matchSequence("OFFSET %f %f %f") )
34        {
35            isRecognized = true;
36            ++fr;
37
38            osg::Vec3 offset;
39            if ( fr.readSequence(offset) )
40            {
41                // Process OFFSET section
42                parent->setBindMatrixInBoneSpace( osg::Matrix::translate(offset) );
43                if ( _drawingFlag && parent->getNumParents() && level>0 )
44                    parent->getParent(0)->addChild( createRefGeometry(offset, 0.5).get() );
45            }
46        }
47
48        if ( fr.matchSequence("CHANNELS %i") )
49        {
50            isRecognized = true;
51
52            // Process CHANNELS section
53            int noChannels;
54            fr[1].getInt( noChannels );
55            fr += 2;
56
57            for ( int i=0; i<noChannels; ++i )
58            {
59                // Process each channel
60                std::string channelName;
61                fr.readSequence( channelName );
62                alterChannel( channelName, _joints.back().second );
63            }
64        }
65
66        if ( fr.matchSequence("End Site {") )
67        {
68            isRecognized = true;
69            fr += 3;
70
71            if ( fr.matchSequence("OFFSET %f %f %f") )
72            {
73                ++fr;
74
75                osg::Vec3 offsetEndSite;
76                if ( fr.readSequence(offsetEndSite) )
77                {
78                    // Process End Site section
79                    osg::ref_ptr<osgAnimation::Bone> bone = new osgAnimation::Bone( parent->getName()+"End" );
80                    bone->setBindMatrixInBoneSpace( osg::Matrix::translate(offsetEndSite) );
81                    bone->setDataVariance( osg::Object::DYNAMIC );
[9371]82                    parent->addChild( bone.get() );
[9304]83
84                    if ( _drawingFlag )
85                        parent->addChild( createRefGeometry(offsetEndSite, 0.5).get() );
86                }
87            }
88            fr.advanceOverCurrentFieldOrBlock();
89        }
90
91        if ( fr.matchSequence("ROOT %w {") || fr.matchSequence("JOINT %w {") )
92        {
93            isRecognized = true;
94
95            // Process JOINT section
96            osg::ref_ptr<osgAnimation::Bone> bone = new osgAnimation::Bone( fr[1].getStr() );
[9370]97            bone->setDefaultUpdateCallback();
[9304]98            bone->setDataVariance( osg::Object::DYNAMIC );
[9371]99            parent->addChild( bone.get() );
[9304]100            _joints.push_back( JointNode(bone, 0) );
101
102            int entry = fr[1].getNoNestedBrackets();
103            fr += 3;
104            while ( !fr.eof() && fr[0].getNoNestedBrackets()>entry )
105                buildHierarchy( fr, entry, bone.get() );
106            fr.advanceOverCurrentFieldOrBlock();
107        }
108
109        if ( !isRecognized )
110        {
111            osg::notify(osg::WARN) << "BVH Reader: Unrecognized symbol " << fr[0].getStr()
112                << ". Ignore current field or block." << std::endl;
113            fr.advanceOverCurrentFieldOrBlock();
114        }
115    }
116
117    void buildMotion( osgDB::Input& fr, osgAnimation::Animation* anim )
118    {
119        int i=0, frames=0;
120        float frameTime=0.033f;
121
122        if ( !fr.readSequence("Frames:", frames) )
123        {
124            osg::notify(osg::WARN) << "BVH Reader: Frame number setting not found, but an unexpected "
125                << fr[0].getStr() << ". Set to 1." << std::endl;
126        }
127
128        ++fr;
129        if ( !fr.readSequence("Time:", frameTime) )
130        {
131            osg::notify(osg::WARN) << "BVH Reader: Frame time setting not found, but an unexpected "
132                << fr[0].getStr() << ". Set to 0.033 (30FPS)." << std::endl;
133        }
134
135        // Each joint has a position animating channel and an euler animating channel
136        std::vector< osg::ref_ptr<osgAnimation::Vec3LinearChannel> > posChannels;
137        std::vector< osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> > rotChannels;
138        for ( JointList::iterator itr=_joints.begin(); itr!=_joints.end(); ++itr )
139        {
140            std::string name = itr->first->getName();
141
142            osg::ref_ptr<osgAnimation::Vec3KeyframeContainer> posKey = new osgAnimation::Vec3KeyframeContainer;
143            osg::ref_ptr<osgAnimation::Vec3LinearSampler> posSampler = new osgAnimation::Vec3LinearSampler;
144            osg::ref_ptr<osgAnimation::Vec3LinearChannel> posChannel = new osgAnimation::Vec3LinearChannel( posSampler.get() );
145            posSampler->setKeyframeContainer( posKey.get() );
146            posChannel->setName( "position" );
147            posChannel->setTargetName( name );
148
149            osg::ref_ptr<osgAnimation::QuatKeyframeContainer> rotKey = new osgAnimation::QuatKeyframeContainer;
150            osg::ref_ptr<osgAnimation::QuatSphericalLinearSampler> rotSampler = new osgAnimation::QuatSphericalLinearSampler;
151            osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> rotChannel = new osgAnimation::QuatSphericalLinearChannel( rotSampler.get() );
152            rotSampler->setKeyframeContainer( rotKey.get() );
153            rotChannel->setName( "quaternion" );
154            rotChannel->setTargetName( name );
155
156            posChannels.push_back( posChannel );
157            rotChannels.push_back( rotChannel );
158        }
159
160        // Obtain motion data from the stream
161        while ( !fr.eof() && i<frames )
162        {
163            for ( unsigned int n=0; n<_joints.size(); ++n )
164            {
165                osgAnimation::Vec3LinearChannel* posChannel = posChannels[n].get();
166                osgAnimation::QuatSphericalLinearChannel* rotChannel = rotChannels[n].get();
167
168                setKeyframe( fr, _joints[n].second, frameTime*(double)i,
169                    dynamic_cast<osgAnimation::Vec3KeyframeContainer*>(posChannel->getSampler()->getKeyframeContainer()),
170                    dynamic_cast<osgAnimation::QuatKeyframeContainer*>(rotChannel->getSampler()->getKeyframeContainer()) );
171            }
172
173            i++;
174        }
175
176        // Add valid channels to the animate object
177        for ( unsigned int n=0; n<_joints.size(); ++n )
178        {
179            if ( posChannels[n]->getOrCreateSampler()->getOrCreateKeyframeContainer()->size()>0 )
180                anim->addChannel( posChannels[n].get() );
181            if ( rotChannels[n]->getOrCreateSampler()->getOrCreateKeyframeContainer()->size()>0 )
182                anim->addChannel( rotChannels[n].get() );
183        }
184    }
185
[9370]186    osg::Group* buildBVH( std::istream& stream, const osgDB::ReaderWriter::Options* options )
[9304]187    {
188        if ( options )
189        {
190            if ( options->getOptionString().find("contours")!=std::string::npos ) _drawingFlag = 1;
191            else if ( options->getOptionString().find("solids")!=std::string::npos ) _drawingFlag = 2;
192        }
193
194        osgDB::Input fr;
195        fr.attach( &stream );
196
197        osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;
[9370]198        skelroot->setDefaultUpdateCallback();
[9304]199        osg::ref_ptr<osgAnimation::Animation> anim = new osgAnimation::Animation;
200
201        while( !fr.eof() )
202        {
203            if ( fr.matchSequence("HIERARCHY") )
204            {
205                ++fr;
206                buildHierarchy( fr, 0, skelroot.get() );
207            }
208            else if ( fr.matchSequence("MOTION") )
209            {
210                ++fr;
211                buildMotion( fr, anim.get() );
212            }
213            else
214            {
215                if ( fr[0].getStr()==NULL ) continue;
216
217                osg::notify(osg::WARN) << "BVH Reader: Unexpected beginning " << fr[0].getStr()
218                    <<  ", neither HIERARCHY nor MOTION. Stopped." << std::endl;
219                break;
220            }
221        }
222
223#if 0
224        std::cout << "Bone number: " << _joints.size() << "\n";
225        for ( unsigned int i=0; i<_joints.size(); ++i )
226        {
227            JointNode node = _joints[i];
228            std::cout << "Bone" << i << " " << node.first->getName() << ": ";
229            std::cout << std::hex << node.second << std::dec << "; ";
230            if ( node.first->getNumParents() )
231                std::cout << "Parent: " << node.first->getParent(0)->getName();
232            std::cout << "\n";
233        }
234#endif
235
[9370]236        osg::Group* root = new osg::Group;
237        osgAnimation::BasicAnimationManager* manager = new osgAnimation::BasicAnimationManager;
238        root->addChild( skelroot.get() );
239        root->setUpdateCallback(manager);
[9304]240        manager->registerAnimation( anim.get() );
241        manager->buildTargetReference();
242        manager->playAnimation( anim.get() );
243
244        _joints.clear();
[9370]245        return root;
[9304]246    }
247
248protected:
249    void alterChannel( std::string name, int& value )
250    {
251        if      ( name=="Xposition" ) value |= 0x01;
252        else if ( name=="Yposition" ) value |= 0x02;
253        else if ( name=="Zposition" ) value |= 0x04;
254        else if ( name=="Zrotation" ) value |= 0x08;
255        else if ( name=="Xrotation" ) value |= 0x10;
256        else if ( name=="Yrotation" ) value |= 0x20;
257    }
258
259    void setKeyframe( osgDB::Input& fr, int ch, double time,
260                      osgAnimation::Vec3KeyframeContainer* posKey,
261                      osgAnimation::QuatKeyframeContainer* rotKey )
262    {
263        if ( ch&0x07 && posKey )  // Position keyframe
264        {
265            float keyValue[3] = { 0.0f };
266            if ( ch&0x01 ) fr.readSequence( keyValue[0] );
267            if ( ch&0x02 ) fr.readSequence( keyValue[1] );
268            if ( ch&0x04 ) fr.readSequence( keyValue[2] );
269
270            osg::Vec3 vec( keyValue[0], keyValue[1], keyValue[2] );
271            posKey->push_back( osgAnimation::Vec3Keyframe(time, vec) );
272        }
273
274        if ( ch&0x38 && rotKey )  // Rotation keyframe
275        {
276            float keyValue[3] = { 0.0f };
277            if ( ch&0x08 ) fr.readSequence( keyValue[2] );
278            if ( ch&0x10 ) fr.readSequence( keyValue[0] );
279            if ( ch&0x20 ) fr.readSequence( keyValue[1] );
280
281            // Note that BVH data need to concatenate the rotating matrices as Y*X*Z
282            // So we should not create Quat directly from input values, which makes a wrong X*Y*Z
283            osg::Matrix rotMat = osg::Matrix::rotate(osg::DegreesToRadians(keyValue[1]), osg::Vec3(0.0,1.0,0.0))
284                               * osg::Matrix::rotate(osg::DegreesToRadians(keyValue[0]), osg::Vec3(1.0,0.0,0.0))
285                               * osg::Matrix::rotate(osg::DegreesToRadians(keyValue[2]), osg::Vec3(0.0,0.0,1.0));
286            osg::Quat quat = rotMat.getRotate();
287            rotKey->push_back( osgAnimation::QuatKeyframe(time, quat) );
288        }
289    }
290
291    osg::ref_ptr<osg::Geode> createRefGeometry( osg::Vec3 p, double len )
292    {
293        osg::ref_ptr<osg::Geode> geode = new osg::Geode; 
294
295        if ( _drawingFlag==1 )
296        {
297            osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
298            osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
299
300            // Joint
301            vertices->push_back( osg::Vec3(-len, 0.0, 0.0) );
302            vertices->push_back( osg::Vec3( len, 0.0, 0.0) );
303            vertices->push_back( osg::Vec3( 0.0,-len, 0.0) );
304            vertices->push_back( osg::Vec3( 0.0, len, 0.0) );
305            vertices->push_back( osg::Vec3( 0.0, 0.0,-len) );
306            vertices->push_back( osg::Vec3( 0.0, 0.0, len) );
307
308            // Bone
309            vertices->push_back( osg::Vec3( 0.0, 0.0, 0.0) );
310            vertices->push_back( p );
311
312            geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 8) );
313            geometry->setVertexArray( vertices.get() );
314
315            geode->addDrawable( geometry.get() );
316        }
317        else if ( _drawingFlag==2 )
318        {
319            osg::Quat quat;
320            osg::ref_ptr<osg::Box> box = new osg::Box( p*0.5, p.length(), len, len );
321            quat.makeRotate( osg::Vec3(1.0,0.0,0.0), p );
322            box->setRotation( quat );
323
324            geode->addDrawable( new osg::ShapeDrawable(box.get()) );
325        }
326       
327        return geode;
328    }
329
330    int _drawingFlag;
331    JointList _joints;
332};
333
334class ReaderWriterBVH : public osgDB::ReaderWriter
335{
336public:
337    ReaderWriterBVH()
338    {
339        supportsExtension( "bvh", "Biovision motion hierarchical file" );
340
341        supportsOption( "contours","Show the skeleton with lines." );
342        supportsOption( "solids","Show the skeleton with solid boxes." );
343    }
344
345    virtual const char* className() const
346    { return "BVH Motion Reader"; }
347
348    virtual ReadResult readNode(std::istream& stream, const osgDB::ReaderWriter::Options* options) const
349    {
350        ReadResult rr = BvhMotionBuilder::instance()->buildBVH( stream, options );
351        return rr;
352    }
353
354    virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
355    {
356        std::string ext = osgDB::getLowerCaseFileExtension( file );
357        if ( !acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;
358
359        std::string fileName = osgDB::findDataFile( file, options );
360        if ( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;
361
362        std::ifstream stream( fileName.c_str(), std::ios::in|std::ios::binary );
363        if( !stream ) return ReadResult::ERROR_IN_READING_FILE;
364        return readNode( stream, options );
365    }
366};
367
368// Now register with Registry to instantiate the above reader/writer.
369REGISTER_OSGPLUGIN( bvh, ReaderWriterBVH )
Note: See TracBrowser for help on using the browser.