1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2009 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 #if __GNUC__ >= 4 || __GNUC_MINOR__ >=3
40 #pragma GCC diagnostic ignored "-Wold-style-cast"
43 #include "OSGColladaController.h"
45 #ifdef OSG_WITH_COLLADA
47 #include "OSGColladaLog.h"
48 #include "OSGColladaGlobal.h"
49 #include "OSGColladaInstanceController.h"
50 #include "OSGColladaSource.h"
51 #include "OSGColladaNode.h"
53 #include "OSGTransform.h"
54 #include "OSGSkinnedGeometry.h"
55 #include "OSGSkeletonJoint.h"
56 #include "OSGNameAttachment.h"
57 #include "OSGFieldContainerUtils.h"
59 #include "OSGTypedGeoVectorProperty.h"
61 #include <dom/domController.h>
62 #include <dom/domGeometry.h>
68 ColladaInstInfoTransitPtr
69 ColladaController::ColladaControllerInstInfo::create(
70 ColladaNode
*colInstParent
, ColladaInstanceController
*colInst
,
73 return ColladaInstInfoTransitPtr(
74 new ColladaControllerInstInfo(colInstParent
, colInst
, parentN
));
78 ColladaController::ColladaControllerInstInfo::process(void)
80 Node
*ctrlInstN
= dynamic_cast<Node
*>(
81 getColInst()->getTargetElem()->createInstance(this));
83 getParentNode()->addChild(ctrlInstN
);
86 ColladaController::ColladaControllerInstInfo::ColladaControllerInstInfo(
87 ColladaNode
*colInstParent
, ColladaInstanceController
*colInst
,
90 : Inherited(colInstParent
, colInst
)
95 ColladaController::ColladaControllerInstInfo::~ColladaControllerInstInfo(void)
99 // ===========================================================================
101 ColladaElementRegistrationHelper
ColladaController::_regHelper(
102 &ColladaController::create
, "controller");
105 ColladaElementTransitPtr
106 ColladaController::create(daeElement
*elem
, ColladaGlobal
*global
)
108 return ColladaElementTransitPtr(new ColladaController(elem
, global
));
112 ColladaController::read(ColladaElement
*colElemParent
)
114 domControllerRef ctrl
= getDOMElementAs
<domController
>();
115 domSkinRef skin
= ctrl
->getSkin();
117 OSG_COLLADA_LOG(("ColladaController::read id [%s]\n", ctrl
->getId()));
121 SWARNING
<< "ColladaController::read: No <skin>" << std::endl
;
129 ColladaController::createInstance(ColladaInstInfo
*colInstInfo
)
131 typedef ColladaInstanceController::MaterialMap ColMaterialMap
;
132 typedef ColladaInstanceController::MaterialMapConstIt ColMaterialMapConstIt
;
134 domControllerRef ctrl
= getDOMElementAs
<domController
>();
136 OSG_COLLADA_LOG(("ColladaController::createInstance id [%s]\n",
139 domSkinRef skin
= ctrl
->getSkin();
140 NodeUnrecPtr groupN
= makeCoredNode
<Group
>();
141 ColladaInstanceControllerRefPtr colInstCtrl
=
142 dynamic_cast<ColladaInstanceController
*>(colInstInfo
->getColInst());
144 if(getGlobal()->getOptions()->getCreateNameAttachments() == true &&
145 ctrl
->getName() != NULL
)
147 setName(groupN
, ctrl
->getName());
152 // find all joints and store them in jointStore
153 JointInfoStore jointStore
;
154 JointIdMap jointIdMap
;
155 resolveJoints(skin
, colInstCtrl
, jointStore
, jointIdMap
);
156 remapJointIds(skin
, colInstCtrl
, jointStore
, jointIdMap
);
158 // create SkinnedGeometry
160 const ColMaterialMap
&matMap
= colInstCtrl
->getMaterialMap();
162 // iterate over all parts of geometry
163 GeoStoreIt gsIt
= _geoStore
.begin();
164 GeoStoreIt gsEnd
= _geoStore
.end ();
166 for(; gsIt
!= gsEnd
; ++gsIt
)
168 OSG_ASSERT(gsIt
->_propStore
.size() == gsIt
->_indexStore
.size());
170 // find the material associated with the geometry's material symbol
171 ColMaterialMapConstIt mmIt
= matMap
.find(gsIt
->_matSymbol
);
172 std::string matTarget
;
174 if(mmIt
!= matMap
.end())
176 matTarget
= mmIt
->second
->getTarget();
179 // can't reuse SkinnedGeometry, it may be instantiated with
180 // a different Skeleton
182 // create new geometry
183 SkinnedGeometryUnrecPtr geo
= SkinnedGeometry::create();
185 getGlobal()->getStatCollector()->getElem(
186 ColladaGlobal::statNGeometryCreated
)->inc();
188 geo
->setLengths(gsIt
->_lengths
);
189 geo
->setTypes (gsIt
->_types
);
191 Inherited::handleBindMaterial(*gsIt
, geo
, colInstCtrl
);
193 geo
->setSkeleton (_skeleton
);
194 geo
->setBindShapeMatrix(_matBindShape
);
195 geo
->setRenderMode (SkinnedGeometry::RMSkinnedGPU
);
197 PropStoreConstIt psIt
= (*gsIt
)._propStore
.begin();
198 PropStoreConstIt psEnd
= (*gsIt
)._propStore
.end ();
200 for(; psIt
!= psEnd
; ++psIt
)
202 if((*psIt
)._semantic
== "JOINT_INDEX")
204 for(UInt16 i
= 0; i
< geo
->getMFProperties()->size(); ++i
)
206 if((*psIt
)._prop
== geo
->getProperty(i
))
208 geo
->setJointIndexProperty(i
);
214 if((*psIt
)._semantic
== "JOINT_WEIGHT")
216 for(UInt16 i
= 0; i
< geo
->getMFProperties()->size(); ++i
)
218 if((*psIt
)._prop
== geo
->getProperty(i
))
220 geo
->setJointWeightProperty(i
);
228 NodeUnrecPtr geoN
= makeNodeFor(geo
);
230 groupN
->addChild(geoN
);
233 // store the generated group node
234 editInstStore().push_back(groupN
);
239 ColladaController::ColladaController(daeElement
*elem
, ColladaGlobal
*global
)
240 : Inherited (elem
, global
)
246 ColladaController::~ColladaController(void)
251 ColladaController::readSkin(domSkin
*skin
)
253 daeURI geoURI
= skin
->getSource();
254 domGeometryRef geo
= daeSafeCast
<domGeometry
>(geoURI
.getElement());
258 SWARNING
<< "ColladaController::readSkin: Could not resolve source "
259 << "URI [" << geoURI
.str() << "] to a <geometry>"
264 domMeshRef mesh
= geo
->getMesh();
268 SWARNING
<< "ColladaController::readSkin: No <mesh> in <geometry>"
273 Inherited::readMesh(mesh
);
275 readBindShapeMatrix(skin
);
277 Inherited::readSources(skin
->getSource_array());
279 // evaluate <vertex_weights>
280 domSkin::domVertex_weightsRef vweights
= skin
->getVertex_weights();
281 const domInputLocalOffset_Array
&inputs
= vweights
->getInput_array();
283 UInt32 jointIdx
= UInt32(inputs
.getCount());
284 ColladaSourceRefPtr weightSrc
= NULL
;
286 for(UInt32 i
= 0; i
< inputs
.getCount(); ++i
)
288 std::string semantic
= inputs
[i
]->getSemantic();
289 std::string sourceId
= inputs
[i
]->getSource ().id();
290 UInt32 offset
= inputs
[i
]->getOffset ();
292 SourceMapConstIt smIt
= _sourceMap
.find(sourceId
);
294 if(smIt
== _sourceMap
.end())
296 SWARNING
<< "ColladaController::readSkin: Could not find "
297 << "<source> with id [" << sourceId
<< "] used by "
298 << "<input> [" << i
<< "] with semantic ["
299 << semantic
<< "]. Ignored." << std::endl
;
303 if(semantic
== "JOINT")
305 // which item of the index tuples in <v> hold the joint
308 else if(semantic
== "WEIGHT")
310 weightSrc
= smIt
->second
;
314 // test if the file has the "usual" form, and only handle that
315 // this means there is an <input> with semantic "JOINT" and
316 // one with semantic "WEIGHT"
317 if(jointIdx
< inputs
.getCount() && weightSrc
!= NULL
&&
318 inputs
.getCount() == 2 )
320 GeoVec4fPropertyUnrecPtr jIndexProp
= GeoVec4fProperty::create();
321 GeoVec4fPropertyUnrecPtr jWeightProp
= GeoVec4fProperty::create();
323 GeoVec4fProperty::StoredFieldType
*jIndexPropF
=
324 jIndexProp
->editFieldPtr();
325 GeoVec4fProperty::StoredFieldType
*jWeightPropF
=
326 jWeightProp
->editFieldPtr();
328 const domListOfUInts
&vcount
= vweights
->getVcount()->getValue();
329 const domListOfInts
&v
= vweights
->getV ()->getValue();
333 for(UInt32 i
= 0; i
< vcount
.getCount(); ++i
)
340 SWARNING
<< "ColladaController::readSkin: Vertex [" << i
341 << "] has [" << vcount
[i
] << "] > 4 weights."
347 // the current vertex i is influenced by vcount[i] many joints
348 for(j
= 0; j
< osgMin
<UInt32
>(4, vcount
[i
]); ++j
)
350 jIndex
[j
] = v
[vIdx
];
351 jWeight
[j
] = weightSrc
->getFloatValue(v
[vIdx
+ 1]);
357 OSG_COLLADA_LOG(("ColladaController::readSkin: vert [%d] "
358 "jIndex [%f %f %f %f] jWeight [%f %f %f %f]\n",
359 i
, jIndex
[0], jIndex
[1], jIndex
[2], jIndex
[3],
360 jWeight
[0], jWeight
[1], jWeight
[2], jWeight
[3]));
363 jIndexPropF
->push_back(jIndex
);
364 jWeightPropF
->push_back(jWeight
);
366 // skip joint/weight indices we can not store (if any)
367 for(j
= osgMin
<UInt32
>(4, vcount
[i
]); j
< vcount
[i
]; ++j
)
373 OSG_COLLADA_LOG(("ColladaController::readSkin: "
374 "jIndexProp.size() [%" PRIUSize
"] "
375 "jWeightProp.size() [%" PRIUSize
"]\n",
377 jWeightProp
->size()));
379 // add jIndexProp and jWeightProp to geoInfos
380 GeoStore::iterator gsIt
= _geoStore
.begin();
381 GeoStore::iterator gsEnd
= _geoStore
.end ();
383 for(UInt32 i
= 0; gsIt
!= gsEnd
; ++gsIt
, ++i
)
385 // add joint index property
386 UInt16 propSlot
= Inherited::findFreePropertyIndex(i
);
387 gsIt
->_propStore
.resize (
388 osgMax
<UInt16
>(UInt16(gsIt
->_propStore
.size()), propSlot
+ 1), PropInfo());
389 gsIt
->_indexStore
.resize(
390 osgMax
<UInt16
>(UInt16(gsIt
->_indexStore
.size()), propSlot
+ 1), NULL
);
392 gsIt
->_propStore
[propSlot
]._prop
= jIndexProp
;
393 gsIt
->_propStore
[propSlot
]._semantic
= "JOINT_INDEX";
394 gsIt
->_propStore
[propSlot
]._set
= 0;
395 gsIt
->_indexStore
[propSlot
] = gsIt
->_indexStore
[0];
397 // add weight property
398 propSlot
= Inherited::findFreePropertyIndex(i
);
399 gsIt
->_propStore
.resize (
400 osgMax
<UInt16
>(UInt16(gsIt
->_propStore
.size()), propSlot
+ 1), PropInfo());
401 gsIt
->_indexStore
.resize(
402 osgMax
<UInt16
>(UInt16(gsIt
->_indexStore
.size()), propSlot
+ 1), NULL
);
404 gsIt
->_propStore
[propSlot
]._prop
= jWeightProp
;
405 gsIt
->_propStore
[propSlot
]._semantic
= "JOINT_WEIGHT";
406 gsIt
->_propStore
[propSlot
]._set
= 0;
407 gsIt
->_indexStore
[propSlot
] = gsIt
->_indexStore
[0];
412 SWARNING
<< "ColladaController::readSkin: Can only handle "
413 << "<vertex_weights> with JOINT and WEIGHT <input>s."
419 ColladaController::readBindShapeMatrix(domSkin
*skin
)
421 domSkin::domBind_shape_matrixRef bsMat
= skin
->getBind_shape_matrix();
425 _matBindShape
.setValue(bsMat
->getValue()[ 0], bsMat
->getValue()[ 1],
426 bsMat
->getValue()[ 2], bsMat
->getValue()[ 3],
427 bsMat
->getValue()[ 4], bsMat
->getValue()[ 5],
428 bsMat
->getValue()[ 6], bsMat
->getValue()[ 7],
429 bsMat
->getValue()[ 8], bsMat
->getValue()[ 9],
430 bsMat
->getValue()[10], bsMat
->getValue()[11],
431 bsMat
->getValue()[12], bsMat
->getValue()[13],
432 bsMat
->getValue()[14], bsMat
->getValue()[15] );
436 _matBindShape
.setIdentity();
439 if(_matBindShape
.equals(Matrix::identity(), Eps
) == true)
443 // transform the properties by the bind shape matrix
445 Matrix
matBindShapeIT(_matBindShape
);
446 matBindShapeIT
.invert ();
447 matBindShapeIT
.transpose();
449 typedef std::set
<GeoVectorProperty
*> PropertySet
;
450 PropertySet xformedProps
;
452 GeoStore::iterator gsIt
= _geoStore
.begin();
453 GeoStore::iterator gsEnd
= _geoStore
.end ();
455 for(; gsIt
!= gsEnd
; ++gsIt
)
457 PropStoreIt psIt
= gsIt
->_propStore
.begin();
458 PropStoreIt psEnd
= gsIt
->_propStore
.end ();
460 for(; psIt
!= psEnd
; ++psIt
)
462 if(psIt
->_prop
== NULL
)
465 // only transform once
466 if(xformedProps
.count(psIt
->_prop
) > 0)
469 if(psIt
->_semantic
== "POSITION")
471 for(UInt32 i
= 0; i
< psIt
->_prop
->size(); ++i
)
475 psIt
->_prop
->getValue(pnt
, i
);
476 _matBindShape
.mult(pnt
, pnt
);
477 psIt
->_prop
->setValue(pnt
, i
);
480 OSG_COLLADA_LOG(("ColladaController::readBindShapeMatrix: "
481 "Transformed property with semantic [%s]\n",
482 psIt
->_semantic
.c_str()));
484 else if(psIt
->_semantic
== "NORMAL")
486 for(UInt32 i
= 0; i
< psIt
->_prop
->size(); ++i
)
490 psIt
->_prop
->getValue(vec
, i
);
491 matBindShapeIT
.mult(vec
, vec
);
492 psIt
->_prop
->setValue(vec
, i
);
495 OSG_COLLADA_LOG(("ColladaController::readBindShapeMatrix: "
496 "Transformed property with semantic [%s]\n",
497 psIt
->_semantic
.c_str()));
501 OSG_COLLADA_LOG(("ColladaController::readBindShapeMatrix: "
502 "Skipped property with semantic [%s]\n",
503 psIt
->_semantic
.c_str()));
506 xformedProps
.insert(psIt
->_prop
);
513 ColladaController::resolveJoints(
514 domSkin
*skin
, ColladaInstanceController
*colInstCtrl
,
515 JointInfoStore
&jointStore
, JointIdMap
&jointIdMap
)
517 domControllerRef ctrl
= getDOMElementAs
<domController
>();
518 domSkin::domJointsRef joints
= skin
->getJoints();
520 // find <input>s with handled semantics (JOINT and INV_BIND_MATRIX)
521 // everything else is ignored/warned about
523 ColladaSourceRefPtr jointSrc
= NULL
;
524 ColladaSourceRefPtr ibmSrc
= NULL
;
526 const domInputLocal_Array
&jointInputs
= joints
->getInput_array();
528 for(UInt32 i
= 0; i
< jointInputs
.getCount(); ++i
)
530 std::string semantic
= jointInputs
[i
]->getSemantic();
531 std::string sourceId
= jointInputs
[i
]->getSource ().id();
533 SourceMapConstIt smIt
= _sourceMap
.find(sourceId
);
535 if(smIt
== _sourceMap
.end())
537 SWARNING
<< "ColladaController::resolveJoints: Could not find "
538 << "<source> with id [" << sourceId
<< "] used by "
539 << "<input> [" << i
<< "] with semantic ["
540 << semantic
<< "]. Ignored." << std::endl
;
544 if(semantic
== "JOINT")
546 jointSrc
= smIt
->second
;
548 else if(semantic
== "INV_BIND_MATRIX")
550 ibmSrc
= smIt
->second
;
554 SWARNING
<< "ColladaController::resolveJoints: Unknown semantic ["
555 << semantic
<< "] on <input> [" << i
<< "]"
562 // resolve joint names to <node>s and fill jointStore
564 if(jointSrc
!= NULL
&& ibmSrc
!= NULL
)
566 const ColladaSource::NameStore
&jointNames
=
567 jointSrc
->getNameStore ();
568 const ColladaSource::MatrixStore
&invBindMats
=
569 ibmSrc
->getMatrixStore();
571 OSG_ASSERT(jointNames
.size() == invBindMats
.size());
573 for(UInt32 i
= 0; i
< jointNames
.size(); ++i
)
576 // joint names are relative to the <skeleton> tags in the
577 // <instance_controller> element
579 domNode
*jointNode
= colInstCtrl
->findJointNode(jointNames
[i
]);
581 if(jointNode
== NULL
)
583 SWARNING
<< "ColladaController::resolveJoints: Could not "
584 << "find <node> for joint name ["
585 << jointNames
[i
] << "] - <controller> ["
586 << (ctrl
->getId() != NULL
? ctrl
->getId() : "")
587 << "]. Ignored." << std::endl
;
591 if(jointNode
->getType() != NODETYPE_JOINT
)
593 SWARNING
<< "ColladaController::resolveJoints: <node> for "
594 << "joint name [" << jointNames
[i
] << "] does not "
595 << "have node type JOINT. Ignored." << std::endl
;
599 ColladaNode
*colJointNode
= getUserDataAs
<ColladaNode
>(jointNode
);
600 OSG_ASSERT(colJointNode
!= NULL
);
602 // store skeleton and ensure all joints belong to the same one
603 if(_skeleton
!= NULL
)
605 if(_skeleton
!= colJointNode
->getSkeleton())
607 SWARNING
<< "ColladaController::resolveJoints: joint ["
608 << i
<< "] name [" << jointNames
[i
]
609 << "] belongs to differente skeleton. Ignoring."
616 _skeleton
= colJointNode
->getSkeleton();
619 if(colJointNode
->getInstStore().size() > 1)
621 SWARNING
<< "ColladaController::resolveJoints: joint ["
622 << i
<< "] name [" << jointNames
[i
]
623 << "] has multiple instances. Using instance 0."
627 SkeletonJoint
*joint
= dynamic_cast<SkeletonJoint
*>(
628 colJointNode
->getBottomNode(0)->getCore());
630 if(joint
->getInvBindMatrix().equals(Matrix::identity(), Eps
) == true)
632 joint
->setInvBindMatrix(invBindMats
[i
]);
634 else if(joint
->getInvBindMatrix().equals(invBindMats
[i
], Eps
) == false)
636 SWARNING
<< "ColladaController::resolveJoints: joint ["
637 << i
<< "] name [" << jointNames
[i
]
638 << "] already has a different inv bind matrix."
642 jointInfo
.jointNode
= jointNode
;
643 jointInfo
.colJointNode
= colJointNode
;
644 jointInfo
.jointId
= joint
->getJointId();
645 jointInfo
.invBindMatrix
= invBindMats
[i
];
647 jointStore
.push_back(jointInfo
);
649 // remember joint id mapping
650 jointIdMap
.push_back(joint
->getJointId());
652 OSG_COLLADA_LOG(("ColladaController::resolveJoints: Resolved "
653 "joint [%d] name [%s] jointId [%d]\n",
654 i
, jointNames
[i
].c_str(), joint
->getJointId() ));
659 SWARNING
<< "ColladaController::resolveJoints: Can only handle "
660 << "<joints> with JOINT and INV_BIND_MATRIX <input>s."
666 ColladaController::remapJointIds(
668 ColladaInstanceController
*colInstCtrl
,
669 const JointInfoStore
&jointStore
,
670 const JointIdMap
&jointIdMap
)
672 typedef std::set
<GeoVectorProperty
*> PropertySet
;
673 PropertySet mappedProps
;
675 GeoStore::iterator gsIt
= _geoStore
.begin();
676 GeoStore::iterator gsEnd
= _geoStore
.end ();
678 for(; gsIt
!= gsEnd
; ++gsIt
)
680 PropStoreIt psIt
= gsIt
->_propStore
.begin();
681 PropStoreIt psEnd
= gsIt
->_propStore
.end ();
683 for(; psIt
!= psEnd
; ++psIt
)
685 if(psIt
->_prop
== NULL
)
688 if(mappedProps
.count(psIt
->_prop
) > 0)
691 if(psIt
->_semantic
!= "JOINT_INDEX")
694 GeoVec4fPropertyUnrecPtr jIndexProp
=
695 dynamic_pointer_cast
<GeoVec4fProperty
>(psIt
->_prop
);
697 GeoVec4fProperty::StoredFieldType
*jIndexPropF
=
698 jIndexProp
->editFieldPtr();
700 for(UInt32 i
= 0; i
< jIndexPropF
->size(); ++i
)
702 Vec4f jIdx
= (*jIndexPropF
)[i
];
704 jIdx
[0] = jointIdMap
[UInt32(jIdx
[0])];
705 jIdx
[1] = jointIdMap
[UInt32(jIdx
[1])];
706 jIdx
[2] = jointIdMap
[UInt32(jIdx
[2])];
707 jIdx
[3] = jointIdMap
[UInt32(jIdx
[3])];
709 (*jIndexPropF
)[i
] = jIdx
;
712 mappedProps
.insert(jIndexProp
);
718 ColladaController::findJoint(
719 const JointInfoStore
&jointStore
, domNode
*joint
)
722 JointInfoStoreConstIt jIt
= jointStore
.begin();
723 JointInfoStoreConstIt jEnd
= jointStore
.end ();
725 for(Int32 i
= 0; jIt
!= jEnd
; ++jIt
, ++i
)
727 if(jIt
->jointNode
== joint
)
739 #endif // OSG_WITH_COLLADA