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 
19 #include <osgAnimation/UpdateMatrixTransform>
20 #include <osgAnimation/StackedMatrixElement>
21 #include <osgAnimation/StackedRotateAxisElement>
22 #include <osgAnimation/StackedScaleElement>
23 #include <osgAnimation/StackedTranslateElement>
24 #include <osg/MatrixTransform>
25 #include <osgSim/DOFTransform>
26 
27 #ifdef COLLADA_DOM_2_4_OR_LATER
28 #include <dom/domAny.h>
29 using namespace ColladaDOM141;
30 #endif
31 
32 using namespace osgDAE;
33 
34 // Note <lookat>, <matrix>, <rotate>, <scale>, <skew> and <translate> may appear in any order
35 // These transformations can be combined in any number and ordering to produce the desired
36 // coordinate system for the parent <node> element. The COLLADA specification requires that the
37 // transformation elements are processed in order and accumulate the result as if they were
38 // converted to column-order matrices and concatenated using matrix post-multiplication.
processOsgMatrixTransform(domNode * node,bool isBone)39 osg::Transform* daeReader::processOsgMatrixTransform(domNode *node, bool isBone)
40 {
41     osg::MatrixTransform* resultNode = NULL;
42 
43     if (isBone)
44     {
45         resultNode = getOrCreateBone(node);
46     }
47     else
48     {
49         resultNode = new osg::MatrixTransform;
50     }
51 
52     osg::Callback* pNodeCallback = resultNode->getUpdateCallback();
53     std::vector<osg::ref_ptr<osgAnimation::StackedTransformElement> > transformElements;
54     osg::ref_ptr<osgAnimation::StackedTransformElement> pLastStaticTransformElement;
55 
56     // Process all coordinate system contributing elements in order!
57     size_t count = node->getContents().getCount();
58     for (size_t i = 0; i < count; i++ )
59     {
60         daeElement* pDaeElement = node->getContents()[i];
61         osg::ref_ptr<osgAnimation::StackedTransformElement> pTransformElement = NULL;
62 
63         if (domRotate * pDomRotate = daeSafeCast< domRotate >( pDaeElement ))
64         {
65             const domFloat4& r = pDomRotate->getValue();
66             if (r.getCount() != 4 )
67             {
68                 OSG_WARN << "Data is wrong size for rotate" << std::endl;
69                 continue;
70             }
71 
72             pTransformElement = new osgAnimation::StackedRotateAxisElement(pDomRotate->getSid() ? pDomRotate->getSid() : "", osg::Vec3(r[0], r[1], r[2]), osg::DegreesToRadians(r[3]));
73         }
74         else if (domTranslate * pDomTranslate = daeSafeCast< domTranslate >( pDaeElement ))
75         {
76             const domFloat3& t = pDomTranslate->getValue();
77             if (t.getCount() != 3 )
78             {
79                 OSG_WARN<<"Data is wrong size for translate"<<std::endl;
80                 continue;
81             }
82 
83             pTransformElement = new osgAnimation::StackedTranslateElement(pDomTranslate->getSid() ?  pDomTranslate->getSid() : "", osg::Vec3(t[0], t[1], t[2]));
84         }
85         else if (domScale * pDomScale = daeSafeCast< domScale >( pDaeElement ))
86         {
87             const domFloat3& s = pDomScale->getValue();
88             if (s.getCount() != 3 )
89             {
90                 OSG_WARN<<"Data is wrong size for scale"<<std::endl;
91                 continue;
92             }
93 
94             pTransformElement = new osgAnimation::StackedScaleElement(pDomScale->getSid() ? pDomScale->getSid() : "", osg::Vec3(s[0], s[1], s[2]));
95         }
96         else if (domMatrix * pDomMatrix = daeSafeCast< domMatrix >( pDaeElement ))
97         {
98             if (pDomMatrix->getValue().getCount() != 16 )
99             {
100                 OSG_WARN<<"Data is wrong size for matrix"<<std::endl;
101                 continue;
102             }
103 
104             pTransformElement = new osgAnimation::StackedMatrixElement(pDomMatrix->getSid() ? pDomMatrix->getSid() : "",
105                 osg::Matrix(    pDomMatrix->getValue()[0], pDomMatrix->getValue()[4], pDomMatrix->getValue()[8], pDomMatrix->getValue()[12],
106                 pDomMatrix->getValue()[1], pDomMatrix->getValue()[5], pDomMatrix->getValue()[9], pDomMatrix->getValue()[13],
107                 pDomMatrix->getValue()[2], pDomMatrix->getValue()[6], pDomMatrix->getValue()[10], pDomMatrix->getValue()[14],
108                 pDomMatrix->getValue()[3], pDomMatrix->getValue()[7], pDomMatrix->getValue()[11], pDomMatrix->getValue()[15]));
109         }
110         else if (domLookat * pDomLookat = daeSafeCast< domLookat >( pDaeElement ))
111         {
112             if (pDomLookat->getValue().getCount() != 9 )
113             {
114                 OSG_WARN<<"Data is wrong size for lookat"<<std::endl;
115                 continue;
116             }
117 
118             pTransformElement = new osgAnimation::StackedMatrixElement(pDomLookat->getSid() ? pDomLookat->getSid() : "",
119                 osg::Matrix::lookAt(
120                 osg::Vec3(pDomLookat->getValue()[0], pDomLookat->getValue()[1], pDomLookat->getValue()[2]),
121                 osg::Vec3(pDomLookat->getValue()[3], pDomLookat->getValue()[4], pDomLookat->getValue()[5]),
122                 osg::Vec3(pDomLookat->getValue()[6], pDomLookat->getValue()[7], pDomLookat->getValue()[8])));
123         }
124         else if (domSkew * pDomSkew = daeSafeCast< domSkew >( pDaeElement ))
125         {
126             if (pDomSkew->getValue().getCount() != 7 )
127             {
128                 OSG_WARN<<"Data is wrong size for skew"<<std::endl;
129                 continue;
130             }
131 
132             const domFloat7& s = pDomSkew->getValue();
133 
134             float shear = sin(osg::DegreesToRadians(s[0]));
135             // axis of rotation
136             osg::Vec3f around(s[1],s[2],s[3]);
137             // axis of translation
138             osg::Vec3f along(s[4],s[5],s[6]);
139 
140             //This maths is untested so may be transposed or negated or just completely wrong.
141             osg::Vec3f normal = along ^ around;
142             normal.normalize();
143             around.normalize();
144             along *= shear / along.length();
145 
146             pTransformElement = new osgAnimation::StackedMatrixElement(pDomSkew->getSid() ? pDomSkew->getSid() : "",
147                 osg::Matrix(
148                 normal.x() * along.x() + 1.0f, normal.x() * along.y(), normal.x() * along.z(), 0.0f,
149                 normal.y() * along.x(), normal.y() * along.y() + 1.0f, normal.y() * along.z(), 0.0f,
150                 normal.z() * along.x(), normal.z() * along.y(), normal.z() * along.z() + 1.0f, 0.0f,
151                 0.0f, 0.0f, 0.0f, 1.0f));
152         }
153 
154         if (pTransformElement)
155         {
156             daeElementDomChannelMap::iterator iter = _daeElementDomChannelMap.find(pDaeElement);
157             if (iter != _daeElementDomChannelMap.end())
158             {
159                 // The element is animated
160 
161                 // First add single or collapsed transform element if any
162                 if (pLastStaticTransformElement)
163                 {
164                     transformElements.push_back(pLastStaticTransformElement);
165                     pLastStaticTransformElement = NULL;
166                 }
167                 transformElements.push_back(pTransformElement);
168 
169                 // Animated element so we need an AnimationUpdateCallback
170                 if (!pNodeCallback)
171                 {
172                     std::string name = node->getId() ? node->getId() : node->getSid() ? node->getSid() : "";
173                     resultNode->setDataVariance(osg::Object::DYNAMIC);
174 
175                     pNodeCallback = new osgAnimation::UpdateMatrixTransform(name);
176                     resultNode->setUpdateCallback(pNodeCallback);
177                 }
178 
179                 do
180                 {
181                     _domChannelOsgAnimationUpdateCallbackMap[iter->second] = pNodeCallback;
182                     ++iter;
183                 } while (iter != _daeElementDomChannelMap.end() && iter->first == pDaeElement);
184             }
185             else if (pLastStaticTransformElement)
186             {
187                 // Add transform element only if not identity
188                 if (!pTransformElement->isIdentity())
189                 {
190                     // Collapse static transform elements
191                     osg::Matrix matrix = pLastStaticTransformElement->getAsMatrix();
192                     pTransformElement->applyToMatrix(matrix);
193                     pLastStaticTransformElement = new osgAnimation::StackedMatrixElement("collapsed", matrix);
194                 }
195             }
196             else if (!pTransformElement->isIdentity())
197             {
198                 // Store single static transform element only if not identity
199                 pLastStaticTransformElement = pTransformElement;
200             }
201         }
202     }
203 
204     // Add final collapsed element (if any)
205     if (pLastStaticTransformElement)
206     {
207         transformElements.push_back(pLastStaticTransformElement);
208     }
209 
210     // Build a matrix for the MatrixTransform and add the elements to the updateCallback
211     osg::Matrix matrix;
212 
213     osgAnimation::UpdateMatrixTransform* pUpdateStackedTransform =
214         dynamic_cast<osgAnimation::UpdateMatrixTransform*>(pNodeCallback);
215 
216     for (size_t i=0; i < transformElements.size(); i++)
217     {
218         transformElements[i]->applyToMatrix(matrix);
219         if (pUpdateStackedTransform)
220         {
221             pUpdateStackedTransform->getStackedTransforms().push_back(transformElements[i].get());
222         }
223     }
224 
225     resultNode->setMatrix(matrix);
226 
227     osg::Vec3 scale = matrix.getScale();
228     if ((scale.x() != 1) || (scale.y() != 1) || (scale.z() != 1))
229     {
230         osg::StateSet* ss = resultNode->getOrCreateStateSet();
231         if (scale.x() == scale.y() && scale.y() == scale.z())
232         {
233             // This mode may be quicker than GL_NORMALIZE, but ONLY works if x, y & z components of scale are the same.
234             ss->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
235         }
236         else
237         {
238             // This mode may be slower than GL_RESCALE_NORMAL, but does work if x, y & z components of scale are not the same.
239             ss->setMode(GL_NORMALIZE, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
240         }
241     }
242 
243     return resultNode;
244 }
245 
processOsgDOFTransform(domTechnique * teq)246 osg::Group* daeReader::processOsgDOFTransform(domTechnique* teq)
247 {
248     osgSim::DOFTransform* dof = new osgSim::DOFTransform;
249 
250     domAny* any = daeSafeCast< domAny >(teq->getChild("MinHPR"));
251     if (any)
252     {
253         dof->setMinHPR(parseVec3String(any->getValue()));
254     }
255     else
256     {
257         OSG_WARN << "Expected element 'MinHPR' not found" << std::endl;
258     }
259 
260     any = daeSafeCast< domAny >(teq->getChild("MaxHPR"));
261     if (any)
262     {
263         dof->setMaxHPR(parseVec3String(any->getValue()));
264     }
265     else
266     {
267         OSG_WARN << "Expected element 'MaxHPR' not found" << std::endl;
268     }
269 
270     any = daeSafeCast< domAny >(teq->getChild("IncrementHPR"));
271     if (any)
272     {
273         dof->setIncrementHPR(parseVec3String(any->getValue()));
274     }
275     else
276     {
277         OSG_WARN << "Expected element 'IncrementHPR' not found" << std::endl;
278     }
279 
280     any = daeSafeCast< domAny >(teq->getChild("CurrentHPR"));
281     if (any)
282     {
283         dof->setCurrentHPR(parseVec3String(any->getValue()));
284     }
285     else
286     {
287         OSG_WARN << "Expected element 'CurrentHPR' not found" << std::endl;
288     }
289 
290     any = daeSafeCast< domAny >(teq->getChild("MinTranslate"));
291     if (any)
292     {
293         dof->setMinTranslate(parseVec3String(any->getValue()));
294     }
295     else
296     {
297         OSG_WARN << "Expected element 'MinTranslate' not found" << std::endl;
298     }
299 
300     any = daeSafeCast< domAny >(teq->getChild("MaxTranslate"));
301     if (any)
302     {
303         dof->setMaxTranslate(parseVec3String(any->getValue()));
304     }
305     else
306     {
307         OSG_WARN << "Expected element 'MaxTranslate' not found" << std::endl;
308     }
309 
310     any = daeSafeCast< domAny >(teq->getChild("IncrementTranslate"));
311     if (any)
312     {
313         dof->setIncrementTranslate(parseVec3String(any->getValue()));
314     }
315     else
316     {
317         OSG_WARN << "Expected element 'IncrementTranslate' not found" << std::endl;
318     }
319 
320     any = daeSafeCast< domAny >(teq->getChild("CurrentTranslate"));
321     if (any)
322     {
323         dof->setCurrentTranslate(parseVec3String(any->getValue()));
324     }
325     else
326     {
327         OSG_WARN << "Expected element 'CurrentTranslate' not found" << std::endl;
328     }
329 
330     any = daeSafeCast< domAny >(teq->getChild("MinScale"));
331     if (any)
332     {
333         dof->setMinScale(parseVec3String(any->getValue()));
334     }
335     else
336     {
337         OSG_WARN << "Expected element 'MinScale' not found" << std::endl;
338     }
339 
340     any = daeSafeCast< domAny >(teq->getChild("MaxScale"));
341     if (any)
342     {
343         dof->setMaxScale(parseVec3String(any->getValue()));
344     }
345     else
346     {
347         OSG_WARN << "Expected element 'MaxScale' not found" << std::endl;
348     }
349 
350     any = daeSafeCast< domAny >(teq->getChild("IncrementScale"));
351     if (any)
352     {
353         dof->setIncrementScale(parseVec3String(any->getValue()));
354     }
355     else
356     {
357         OSG_WARN << "Expected element 'IncrementScale' not found" << std::endl;
358     }
359 
360     any = daeSafeCast< domAny >(teq->getChild("CurrentScale"));
361     if (any)
362     {
363         dof->setCurrentScale(parseVec3String(any->getValue()));
364     }
365     else
366     {
367         OSG_WARN << "Expected element 'CurrentScale' not found" << std::endl;
368     }
369 
370     any = daeSafeCast< domAny >(teq->getChild("MultOrder"));
371     if (any)
372     {
373         dof->setHPRMultOrder((osgSim::DOFTransform::MultOrder)parseString<int>(any->getValue()));
374     }
375     else
376     {
377         OSG_WARN << "Expected element 'MultOrder' not found" << std::endl;
378     }
379 
380     any = daeSafeCast< domAny >(teq->getChild("LimitationFlags"));
381     if (any)
382     {
383         dof->setLimitationFlags(parseString<unsigned long>(any->getValue()));
384     }
385     else
386     {
387         OSG_WARN << "Expected element 'LimitationFlags' not found" << std::endl;
388     }
389 
390     any = daeSafeCast< domAny >(teq->getChild("AnimationOn"));
391     if (any)
392     {
393         dof->setAnimationOn(parseString<bool>(any->getValue()));
394     }
395     else
396     {
397         OSG_WARN << "Expected element 'AnimationOn' not found" << std::endl;
398     }
399 
400     any = daeSafeCast< domAny >(teq->getChild("PutMatrix"));
401     if (any)
402     {
403         osg::Matrix mat = parseMatrixString(any->getValue());
404         dof->setPutMatrix(mat);
405         dof->setInversePutMatrix( osg::Matrixd::inverse( mat ) );
406     }
407     else
408     {
409         OSG_WARN << "Expected element 'PutMatrix' not found" << std::endl;
410     }
411 
412     return dof;
413 }
414