root/OpenSceneGraph/trunk/src/osgPlugins/dae/daeReader.cpp @ 13041

Revision 13041, 22.1 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Copyright 2006 Sony Computer Entertainment Inc.
3 *
4 * Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this
5 * file except in compliance with the License. You may obtain a copy of the License at:
6 * http://research.scea.com/scea_shared_source_license.html
7 *
8 * Unless required by applicable law or agreed to in writing, software distributed under the License
9 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
10 * implied. See the License for the specific language governing permissions and limitations under the
11 * License.
12 */
13
14#include "daeReader.h"
15#include <dae.h>
16#include <dae/domAny.h>
17#include <dom/domCOLLADA.h>
18#include <dom/domInstanceWithExtra.h>
19#include <dom/domConstants.h>
20#include <osg/MatrixTransform>
21#include <osg/PositionAttitudeTransform>
22
23using namespace osgDAE;
24
25daeReader::Options::Options() :
26    strictTransparency(false),
27    precisionHint(0),
28    usePredefinedTextureUnits(true),
29    tessellateMode(TESSELLATE_POLYGONS_AS_TRIFAN)   // Use old tessellation behaviour as default
30{
31}
32
33daeReader::daeReader(DAE *dae_, const Options * pluginOptions) :
34                  _dae(dae_),
35                  _rootNode(NULL),
36                  _document(NULL),
37                  _visualScene(NULL),
38                  _numlights(0),
39                  _currentInstance_effect(NULL),
40                  _currentEffect(NULL),
41                  _authoringTool(UNKNOWN),
42                  _invertTransparency(false),
43                  _pluginOptions(pluginOptions ? *pluginOptions : Options()),
44                  _assetUnitName("meter"),
45                  _assetUnitMeter(1.0),
46                  _assetUp_axis(UPAXISTYPE_Y_UP)
47{
48}
49
50daeReader::~daeReader()
51{
52}
53
54bool daeReader::convert( const std::string &fileURI )
55{
56    // Clear caches
57    _geometryMap.clear();
58    _materialMap.clear();
59    _materialMap2.clear();
60
61    daeElement *colladaElement;
62
63
64    daeInt count, result;
65
66    _document = _dae->open(fileURI);
67
68    if (!_document)
69    {
70        OSG_WARN << "Load failed in COLLADA DOM" << std::endl;
71        return false;
72    }
73    OSG_INFO << "URI loaded: " << fileURI << std::endl;
74
75    if ( !_document->getScene() || !_document->getScene()->getInstance_visual_scene() )
76    {
77        OSG_WARN << "No scene found!" << std::endl;
78        return false;
79    }
80
81    if (_document->getAsset())
82    {
83        const domAsset::domContributor_Array& ContributorArray = _document->getAsset()->getContributor_array();
84        size_t NumberOfContributors = ContributorArray.getCount();
85        size_t CurrentContributor;
86        for (CurrentContributor = 0; CurrentContributor < NumberOfContributors; CurrentContributor++)
87        {
88            if (ContributorArray[CurrentContributor]->getAuthoring_tool())
89            {
90                const char szBlender[] = "Blender";
91                const char szDazStudio[] = "DAZ|Studio";
92                const char szSketchup[] = "Google SketchUp";
93                const char szFbx[] = "FBX";
94                const char szMaya[] = "Maya";
95
96                xsString Tool = ContributorArray[CurrentContributor]->getAuthoring_tool()->getValue();
97
98                if (strncmp(Tool, szBlender, strlen(szBlender)) == 0)
99                    _authoringTool = BLENDER;
100                else if (strncmp(Tool, szDazStudio, strlen(szDazStudio)) == 0)
101                    _authoringTool = DAZ_STUDIO;
102                else if (strncmp(Tool, szFbx, strlen(szFbx)) == 0)
103                    _authoringTool = FBX_CONVERTER;
104                else if (strncmp(Tool, szSketchup, strlen(szSketchup)) == 0)
105                    _authoringTool = GOOGLE_SKETCHUP;
106                else if (strncmp(Tool, szMaya, strlen(szMaya)) == 0)
107                    _authoringTool = MAYA;
108            }
109        }
110        if (_document->getAsset()->getUnit())
111        {
112            if (NULL != _document->getAsset()->getUnit()->getName())
113                _assetUnitName = std::string(_document->getAsset()->getUnit()->getName());
114            if (0 != _document->getAsset()->getUnit()->getMeter())
115                _assetUnitMeter = _document->getAsset()->getUnit()->getMeter();
116        }
117        if (_document->getAsset()->getUp_axis())
118            _assetUp_axis = _document->getAsset()->getUp_axis()->getValue();
119    }
120
121    domInstanceWithExtra *ivs = _document->getScene()->getInstance_visual_scene();
122    _visualScene = daeSafeCast< domVisual_scene >( getElementFromURI( ivs->getUrl() ) );
123    if ( _visualScene == NULL )
124    {
125        OSG_WARN << "Unable to locate visual scene!" << std::endl;
126        return false;
127    }
128
129    if (daeDatabase* database = _dae->getDatabase())
130    {
131        _invertTransparency = findInvertTransparency(database);
132
133        // build a std::map for lookup if Group or PositionAttitudeTransform should be created,
134        // i.e, make it easy to check if a instance_rigid_body targets a visual node
135        domInstance_rigid_body *pDomInstanceRigidBody;
136        count = database->getElementCount(NULL, COLLADA_TYPE_INSTANCE_RIGID_BODY, NULL);
137        for (int i=0; i<count; i++)
138        {
139            result = database->getElement(&colladaElement, i, NULL, COLLADA_TYPE_INSTANCE_RIGID_BODY);
140
141            if (result == DAE_OK)
142            {
143                pDomInstanceRigidBody = daeSafeCast<domInstance_rigid_body>(colladaElement);
144                if (pDomInstanceRigidBody)
145                {
146                    domNode *node = daeSafeCast<domNode>(pDomInstanceRigidBody->getTarget().getElement());
147                    if (node && node->getId())
148                    {
149                        _targetMap[ std::string(node->getId()) ] = true;
150                    }
151                }
152            }
153        }
154
155        // Build a map of elements that are targetted by animations
156        count = database->getElementCount(NULL, COLLADA_TYPE_CHANNEL, NULL);
157        for (int i=0; i<count; i++)
158        {
159            result = database->getElement(&colladaElement, i, NULL, COLLADA_TYPE_CHANNEL);
160
161            if (result == DAE_OK)
162            {
163                domChannel* pDomChannel = daeSafeCast<domChannel>(colladaElement);
164                if (pDomChannel)
165                {
166                    std::string target = pDomChannel->getTarget();
167                    size_t openparenthesis = target.find_first_of('(');
168                    if (openparenthesis != std::string::npos) target.erase(openparenthesis);
169                    daeSIDResolver resolver(pDomChannel, target.c_str());
170                    daeElement *pDaeElement = resolver.getElement();
171                    if (pDaeElement)
172                    {
173                        _daeElementDomChannelMap.insert(daeElementDomChannelMap::value_type(pDaeElement, pDomChannel));
174                    }
175                    else
176                    {
177                        OSG_WARN << "Could not locate <channel> target "  << pDomChannel->getTarget()<< std::endl;
178                    }
179                }
180            }
181        }
182
183        // Find all nodes that are used as bones. Note that while many files
184        // identify nodes with type="JOINT", some don't do this, while others
185        // identify every node as a joint, making it meaningless.
186        std::vector<domInstance_controller*> instanceControllers;
187        database->typeLookup(instanceControllers);
188        for (size_t i = 0; i < instanceControllers.size(); ++i)
189        {
190            domInstance_controller* pInstanceController = instanceControllers[i];
191
192            domController *pDomController = daeSafeCast<domController>(getElementFromURI(pInstanceController->getUrl()));
193            if (!pDomController)
194            {
195                OSG_WARN << "Failed to locate controller " << pInstanceController->getUrl().getURI() << std::endl;
196                continue;
197            }
198
199            const domInstance_controller::domSkeleton_Array& domSkeletonURIs = pInstanceController->getSkeleton_array();
200            std::vector<daeElement*> searchIn;
201
202            for (size_t i = 0; i < domSkeletonURIs.getCount(); ++i)
203            {
204                if (daeElement* el = getElementFromURI(domSkeletonURIs[i]->getValue()))
205                {
206                    searchIn.push_back(el);
207                    if (domNode* pJoint = daeSafeCast<domNode>(el))
208                    {
209                        _jointSet.insert(pJoint);
210                    }
211                }
212            }
213
214            if (searchIn.empty())
215            {
216                searchIn.push_back(_visualScene);
217            }
218
219            const domSkin* pSkin = pDomController->getSkin();
220            if (!pSkin) continue;
221            const domSkin::domJoints* pJoints = pSkin->getJoints();
222            if (!pJoints) continue;
223            const domInputLocal_Array& inputURIs = pJoints->getInput_array();
224
225            domSource* pDomJointsSource = NULL;
226            for (size_t i=0; i < inputURIs.getCount(); i++)
227            {
228                if (!strcmp(inputURIs[i]->getSemantic(), COMMON_PROFILE_INPUT_JOINT))
229                {
230                    pDomJointsSource = daeSafeCast<domSource>(getElementFromURI(inputURIs[i]->getSource()));
231                    if (!pDomJointsSource)
232                    {
233                        OSG_WARN << "Could not find skin joints source '" << inputURIs[i]->getSource().getURI() << "'" <<std::endl;
234                    }
235                }
236            }
237
238            if (!pDomJointsSource)
239            {
240            }
241            else if (domIDREF_array* pDomIDREFs = pDomJointsSource->getIDREF_array())
242            {
243                for (size_t i = 0; i < pDomIDREFs->getCount(); ++i)
244                {
245                    if (domNode* pJoint = daeSafeCast<domNode>(getElementFromIDRef(pDomIDREFs->getValue().get(i))))
246                    {
247                        _jointSet.insert(pJoint);
248                    }
249                }
250            }
251            else if (domName_array* pDomNames = pDomJointsSource->getName_array())
252            {
253                for (size_t i = 0; i < pDomNames->getCount(); ++i)
254                {
255                    daeString target = pDomNames->getValue().get(i);
256                    for (size_t j = 0; j < searchIn.size(); ++j)
257                    {
258                        daeSIDResolver resolver(searchIn[j], target);
259                        if (domNode* pJoint = daeSafeCast<domNode>(resolver.getElement()))
260                        {
261                            _jointSet.insert(pJoint);
262                        }
263                    }
264                }
265            }
266        }
267    }
268
269    // Build the actual scene graph based on the visual scene
270    _rootNode = processVisualScene( _visualScene );
271
272    osgAnimation::BasicAnimationManager* pOsgAnimationManager = processAnimationLibraries(_document);
273    if (pOsgAnimationManager)
274    {
275        _rootNode->addUpdateCallback(pOsgAnimationManager);
276    }
277
278    return true;
279}
280
281void daeReader::addChild(osg::Group* group, osg::Node* node)
282{
283    if (dynamic_cast<osgAnimation::Bone*>(node))
284    {
285        unsigned index = 0;
286        while (index < group->getNumChildren() &&
287            dynamic_cast<osgAnimation::Bone*>(group->getChild(index)))
288        {
289            ++index;
290        }
291        group->insertChild(index, node);
292    }
293    else
294    {
295        group->addChild(node);
296    }
297}
298
299osg::Group* daeReader::turnZUp()
300{
301    osg::PositionAttitudeTransform* pat = NULL;
302
303    // If not Z axis up we need to rotate scene to bring the Z axis up
304    if (_assetUp_axis != UPAXISTYPE_Z_UP)
305    {
306        pat = new osg::PositionAttitudeTransform();
307        if (_assetUp_axis == UPAXISTYPE_Y_UP)
308        {
309            pat->setAttitude(osg::Quat(osg::inDegrees(90.0f), osg::Vec3(1.0f,0.0f,0.0f)));
310        }
311        else //(m_AssetUp_axis == UPAXISTYPE_X_UP)
312        {
313            pat->setAttitude(osg::Quat(osg::inDegrees(90.0f), osg::Vec3(0.0f,1.0f,0.0f)));
314        }
315    }
316
317    _assetUp_axis = UPAXISTYPE_Z_UP;
318    return pat;
319}
320
321osg::Group* daeReader::processVisualScene( domVisual_scene *scene )
322{
323    osg::Group *retVal;
324    _rootStateSet = new osg::StateSet();
325
326    unsigned int nbVisualSceneGroup=scene->getNode_array().getCount();
327    if (nbVisualSceneGroup==0)
328    {
329        OSG_WARN << "No visual scene group found !" << std::endl;
330        retVal = new osg::Group();
331        retVal->setName("Empty Collada scene");
332    }
333    else
334    {
335        retVal = turnZUp();
336
337        if (!retVal)
338        {
339            retVal = new osg::Group;
340        }
341
342        _skinInstanceControllers.clear();
343
344        const domNode_Array& node_array = scene->getNode_array();
345        for (size_t i = 0; i < node_array.getCount(); i++)
346        {
347            if (osg::Node* node = processNode(node_array[i], false))
348            {
349                addChild(retVal, node);
350            }
351        }
352
353        processSkins();
354
355        if (retVal->getName().empty())
356        {
357            if (retVal->getNumChildren())
358            {
359                retVal->setName("Collada visual scene group");
360            }
361            else
362            {
363                retVal->setName("Empty Collada scene (import failure)");
364            }
365        }
366    }
367    retVal->setStateSet(_rootStateSet.get());
368
369    return retVal;
370}
371
372
373
374osg::Group* daeReader::processExtras(domNode *node)
375{
376    // See if one of the extras contains OpenSceneGraph specific information
377    unsigned int numExtras = node->getExtra_array().getCount();
378    for (unsigned int currExtra=0; currExtra < numExtras; currExtra++)
379    {
380        domExtra* extra = node->getExtra_array()[currExtra];
381        domTechnique* teq = NULL;
382
383        daeString extraType = extra->getType();
384        if (extraType)
385        {
386            if (strcmp(extraType, "Switch") == 0)
387            {
388                teq = getOpenSceneGraphProfile(extra);
389                if (teq)
390                {
391                    return processOsgSwitch(teq);
392                }
393            }
394            else if (strcmp(extraType, "MultiSwitch") == 0)
395            {
396                teq = getOpenSceneGraphProfile(extra);
397                if (teq)
398                {
399                    return processOsgMultiSwitch(teq);
400                }
401            }
402            else if (strcmp(extraType, "LOD") == 0)
403            {
404                teq = getOpenSceneGraphProfile(extra);
405                if (teq)
406                {
407                    return processOsgLOD(teq);
408                }
409            }
410            else if (strcmp(extraType, "DOFTransform") == 0)
411            {
412                teq = getOpenSceneGraphProfile(extra);
413                if (teq)
414                {
415                    return processOsgDOFTransform(teq);
416                }
417            }
418            else if (strcmp(extraType, "Sequence") == 0)
419            {
420                teq = getOpenSceneGraphProfile(extra);
421                if (teq)
422                {
423                    return processOsgSequence(teq);
424                }
425            }
426        }
427    }
428    return new osg::Group;
429}
430
431void daeReader::processNodeExtra(osg::Node* osgNode, domNode *node)
432{
433    // See if one of the extras contains OpenSceneGraph specific information
434    unsigned int numExtras = node->getExtra_array().getCount();
435
436    for (unsigned int currExtra=0; currExtra < numExtras; currExtra++)
437    {
438        domExtra* extra = node->getExtra_array()[currExtra];
439
440        daeString extraType = extra->getType();
441        if (extraType && (strcmp(extraType, "Node") == 0))
442        {
443            domTechnique* teq = getOpenSceneGraphProfile(extra);
444            if (teq)
445            {
446                domAny* any = daeSafeCast< domAny >(teq->getChild("Descriptions"));
447                if (any)
448                {
449                    osg::Node::DescriptionList descriptions;
450                    unsigned int numChildren = any->getChildren().getCount();
451                    for (unsigned int currChild = 0; currChild < numChildren; currChild++)
452                    {
453                        domAny* child = daeSafeCast<domAny>(any->getChildren()[currChild]);
454                        if (child)
455                        {
456                            if (strcmp(child->getElementName(), "Description" ) == 0 )
457                            {
458                                std::string value = child->getValue();
459                                descriptions.push_back(value);
460                            }
461                            else
462                            {
463                                OSG_WARN << "Child of element 'Descriptions' is not of type 'Description'" << std::endl;
464                            }
465                        }
466                        else
467                        {
468                            OSG_WARN << "Element 'Descriptions' does not contain expected elements." << std::endl;
469                        }
470                    }
471                    osgNode->setDescriptions(descriptions);
472                }
473                else
474                {
475                    OSG_WARN << "Expected element 'Descriptions' not found" << std::endl;
476                }
477            }
478        }
479    }
480}
481
482domTechnique* daeReader::getOpenSceneGraphProfile(domExtra* extra)
483{
484    unsigned int numTeqs = extra->getTechnique_array().getCount();
485
486    for ( unsigned int currTeq = 0; currTeq < numTeqs; ++currTeq )
487    {
488        // Only interested in OpenSceneGraph technique
489        if (strcmp( extra->getTechnique_array()[currTeq]->getProfile(), "OpenSceneGraph" ) == 0 )
490        {
491            return extra->getTechnique_array()[currTeq];
492        }
493    }
494    return NULL;
495}
496
497
498// <node>
499// attributes:
500// id, name, sid, type, layer
501// child elements:
502// 0..1 <asset>
503// 0..* <lookat>, <matrix>, <rotate>, <scale>, <skew>, <translate>
504// 0..* <instance_camera>
505// 0..* <instance_controller>
506// 0..* <instance_geometry>
507// 0..* <instance_light>
508// 0..* <instance_node>
509// 0..* <node>
510// 0..* <extra>
511osg::Node* daeReader::processNode( domNode *node, bool skeleton)
512{
513    // First we need to determine what kind of OSG node we need
514    // If there exist any of the <lookat>, <matrix>, <rotate>, <scale>, <skew>, <translate> elements
515    // or if a COLLADA_TYPE_INSTANCE_RIGID_BODY targets this node we need a MatrixTransform
516    int coordcount =    node->getRotate_array().getCount() +
517                        node->getScale_array().getCount() +
518                        node->getTranslate_array().getCount() +
519                        node->getLookat_array().getCount() +
520                        node->getMatrix_array().getCount() +
521                        node->getSkew_array().getCount();
522
523    // See if it is targeted by an animation
524    bool targeted = false;
525    if (node->getId())
526    {
527        targeted = _targetMap[std::string(node->getId())];
528    }
529
530
531    osg::Group *resultNode = NULL;
532
533    bool isBone = skeleton || isJoint(node);
534
535    if (coordcount > 0 || targeted || isBone)
536    {
537        // TODO
538        // single matrix -> MatrixTransform
539        // scale, euler, translate -> PositionAttitudeTransform
540        // if targeted -> StackedTransform
541        // otherwise a flattened -> MatrixTransform
542        resultNode = processOsgMatrixTransform(node, isBone);
543    }
544    else
545    {
546        // No transform data, determine node type based on it's available extra data
547        resultNode = processExtras(node);
548    }
549
550    // See if there is generic node info attached as extra
551    processNodeExtra(resultNode, node);
552
553    if (resultNode->getName().empty())
554    {
555        std::string name = "";
556        if (node->getId())
557            name = node->getId();
558        if (node->getName())
559            name = node->getName();
560        resultNode->setName( name );
561    }
562
563    osg::Group* attachTo = resultNode;
564
565    if (!skeleton && isJoint(node))
566    {
567        skeleton = true;
568        osgAnimation::Skeleton* pOsgSkeleton = getOrCreateSkeleton(node);
569        pOsgSkeleton->addChild(resultNode);
570        attachTo = resultNode;
571        resultNode = pOsgSkeleton;
572    }
573
574    // 0..* <instance_camera>
575    const domInstance_camera_Array& cameraInstanceArray = node->getInstance_camera_array();
576    for ( size_t i = 0; i < cameraInstanceArray.getCount(); i++ )
577    {
578        daeElement *el = getElementFromURI( cameraInstanceArray[i]->getUrl());
579        domCamera *c = daeSafeCast< domCamera >( el );
580
581        if (c)
582            addChild(attachTo, processCamera( c ));
583        else
584            OSG_WARN << "Failed to locate camera " << cameraInstanceArray[i]->getUrl().getURI() << std::endl;
585    }
586
587    // 0..* <instance_controller>
588    const domInstance_controller_Array& controllerInstanceArray = node->getInstance_controller_array();
589    for ( size_t i = 0; i < controllerInstanceArray.getCount(); i++ )
590    {
591        osg::Node* pOsgNode = processInstanceController( controllerInstanceArray[i]);
592
593        // A skin controller may return NULL,  since the RigGeometry is added as
594        // child of the skeleton and the skeleton already is added to the scenegraph
595        if (pOsgNode)
596        {
597            addChild(attachTo, pOsgNode);
598        }
599    }
600
601    // 0..* <instance_geometry>
602    const domInstance_geometry_Array& geometryInstanceArray = node->getInstance_geometry_array();
603    for ( size_t i = 0; i < geometryInstanceArray.getCount(); i++ )
604    {
605        addChild(attachTo, processInstanceGeometry( geometryInstanceArray[i] ));
606    }
607
608    // 0..* <instance_light>
609    const domInstance_light_Array& lightInstanceArray = node->getInstance_light_array();
610    for ( size_t i = 0; i < lightInstanceArray.getCount(); i++ )
611    {
612        daeElement *el = getElementFromURI( lightInstanceArray[i]->getUrl());
613        domLight *pDomLight = daeSafeCast< domLight >( el );
614
615        if (pDomLight)
616            addChild(attachTo, processLight(pDomLight));
617        else
618            OSG_WARN << "Failed to locate light " << lightInstanceArray[i]->getUrl().getURI() << std::endl;
619    }
620
621    // 0..* <instance_node>
622    const domInstance_node_Array& nodeInstanceArray = node->getInstance_node_array();
623    for ( size_t i = 0; i < nodeInstanceArray.getCount(); i++ )
624    {
625        daeElement *el = getElementFromURI( nodeInstanceArray[i]->getUrl());
626        domNode *n = daeSafeCast< domNode >( el );
627
628        if (n)
629            // Recursive call
630            addChild(attachTo, processNode( n, skeleton ));
631        else
632            OSG_WARN << "Failed to locate node " << nodeInstanceArray[i]->getUrl().getURI() << std::endl;
633    }
634
635    // 0..* <node>
636    const domNode_Array& nodeArray = node->getNode_array();
637    for ( size_t i = 0; i < nodeArray.getCount(); i++ )
638    {
639        // Recursive call
640        addChild(attachTo, processNode( nodeArray[i], skeleton ));
641    }
642
643    return resultNode;
644}
Note: See TracBrowser for help on using the browser.