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