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 <osg/Switch>
20 #include <osg/LightSource>
21 #include <osg/Geode>
22 #include <osg/ShapeDrawable>
23 #include <osg/LOD>
24 #include <osg/Billboard>
25 #include <osgSim/MultiSwitch>
26 #include <osg/Sequence>
27 #include <osg/CameraView>
28 #include <osg/LightModel>
29 
30 using namespace osgDAE;
31 
32 #ifdef COLLADA_DOM_2_4_OR_LATER
33 #include <dom/domAny.h>
34 using namespace ColladaDOM141;
35 #endif
36 
processOsgMultiSwitch(domTechnique * teq)37 osg::Group* daeReader::processOsgMultiSwitch(domTechnique* teq)
38 {
39     osgSim::MultiSwitch* msw = new osgSim::MultiSwitch;
40 
41     domAny* any = daeSafeCast<domAny>(teq->getChild("ActiveSwitchSet"));
42     if (any)
43     {
44         msw->setActiveSwitchSet(parseString<unsigned int>(any->getValue()));
45     }
46     else
47     {
48         OSG_WARN << "Expected element 'ActiveSwitchSet' not found" << std::endl;
49     }
50 
51     any = daeSafeCast<domAny>(teq->getChild("ValueLists"));
52     if (any)
53     {
54         unsigned int numChildren = any->getChildren().getCount();
55         for (unsigned int currChild = 0; currChild < numChildren; currChild++)
56         {
57             domAny* child = daeSafeCast<domAny>(any->getChildren()[currChild]);
58             if (child)
59             {
60                 if (strcmp(child->getElementName(), "ValueList" ) == 0 )
61                 {
62                     std::list<std::string> stringValues;
63                     osgSim::MultiSwitch::ValueList values;
64 
65                     cdom::tokenize(child->getValue(), " ", stringValues);
66                     cdom::tokenIter iter = stringValues.begin();
67 
68                     while (iter != stringValues.end())
69                     {
70                         values.push_back(parseString<bool>(*iter));
71                         ++iter;
72                     }
73 
74                     msw->setValueList(currChild, values);
75                 }
76                 else
77                 {
78                     OSG_WARN << "Child of element 'ValueLists' is not of type 'ValueList'" << std::endl;
79                 }
80             }
81             else
82             {
83                 OSG_WARN << "Element 'ValueLists' does not contain expected elements." << std::endl;
84             }
85         }
86     }
87     else
88     {
89         OSG_WARN << "Expected element 'ValueLists' not found" << std::endl;
90     }
91     return msw;
92 }
93 
processOsgSwitch(domTechnique * teq)94 osg::Group* daeReader::processOsgSwitch(domTechnique* teq)
95 {
96     osg::Switch* sw = new osg::Switch;
97 
98     domAny* any = daeSafeCast< domAny >(teq->getChild("ValueList"));
99     if (any)
100     {
101         std::list<std::string> stringValues;
102 
103         cdom::tokenize(any->getValue(), " ", stringValues);
104         cdom::tokenIter iter = stringValues.begin();
105 
106         int pos = 0;
107         while (iter != stringValues.end())
108         {
109             sw->setValue(pos++, parseString<bool>(*iter));
110             ++iter;
111         }
112     }
113     else
114     {
115         OSG_WARN << "Expected element 'ValueList' not found" << std::endl;
116     }
117     return sw;
118 }
119 
processOsgSequence(domTechnique * teq)120 osg::Group* daeReader::processOsgSequence(domTechnique* teq)
121 {
122     osg::Sequence* sq = new osg::Sequence;
123 
124     domAny* any = daeSafeCast< domAny >(teq->getChild("FrameTime"));
125     if (any)
126     {
127         std::list<std::string> stringValues;
128 
129         cdom::tokenize(any->getValue(), " ", stringValues);
130         cdom::tokenIter iter = stringValues.begin();
131 
132         int frame = 0;
133         while (iter != stringValues.end())
134         {
135             sq->setTime(frame++, parseString<double>(*iter));
136             ++iter;
137         }
138     }
139     else
140     {
141         OSG_WARN << "Expected element 'FrameTime' not found" << std::endl;
142     }
143 
144     any = daeSafeCast< domAny >(teq->getChild("LastFrameTime"));
145     if (any)
146     {
147         sq->setLastFrameTime(parseString<double>(any->getValue()));
148     }
149     else
150     {
151         OSG_WARN << "Expected element 'LastFrameTime' not found" << std::endl;
152     }
153 
154     osg::Sequence::LoopMode loopmode = osg::Sequence::LOOP;
155     any = daeSafeCast< domAny >(teq->getChild("LoopMode"));
156     if (any)
157     {
158         loopmode = (osg::Sequence::LoopMode)parseString<int>(any->getValue());
159     }
160     else
161     {
162         OSG_WARN << "Expected element 'LoopMode' not found" << std::endl;
163     }
164 
165     int begin=0;
166     any = daeSafeCast< domAny >(teq->getChild("IntervalBegin"));
167     if (any)
168     {
169         begin = parseString<int>(any->getValue());
170     }
171     else
172     {
173         OSG_WARN << "Expected element 'IntervalBegin' not found" << std::endl;
174     }
175 
176     int end=-1;
177     any = daeSafeCast< domAny >(teq->getChild("IntervalEnd"));
178     if (any)
179     {
180         end = parseString<int>(any->getValue());
181     }
182     else
183     {
184         OSG_WARN << "Expected element 'IntervalEnd' not found" << std::endl;
185     }
186 
187     sq->setInterval(loopmode, begin, end);
188 
189     float speed = 0;
190     any = daeSafeCast< domAny >(teq->getChild("DurationSpeed"));
191     if (any)
192     {
193         speed = parseString<float>(any->getValue());
194     }
195     else
196     {
197         OSG_WARN << "Expected element 'DurationSpeed' not found" << std::endl;
198     }
199 
200     int nreps = -1;
201     any = daeSafeCast< domAny >(teq->getChild("DurationNReps"));
202     if (any)
203     {
204         nreps = parseString<int>(any->getValue());
205     }
206     else
207     {
208         OSG_WARN << "Expected element 'DurationNReps' not found" << std::endl;
209     }
210 
211     sq->setDuration(speed, nreps);
212 
213     any = daeSafeCast< domAny >(teq->getChild("SequenceMode"));
214     if (any)
215     {
216         sq->setMode((osg::Sequence::SequenceMode)parseString<int>(any->getValue()));
217     }
218     else
219     {
220         OSG_WARN << "Expected element 'SequenceMode' not found" << std::endl;
221     }
222 
223     return sq;
224 }
225 
226 
processOsgLOD(domTechnique * teq)227 osg::Group* daeReader::processOsgLOD(domTechnique* teq)
228 {
229     osg::LOD* lod = new osg::LOD;
230 
231     domAny* any = daeSafeCast< domAny >(teq->getChild("Center"));
232     if (any)
233     {
234         // If a center is specified
235         lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER);
236         lod->setCenter(parseVec3String(any->getValue()));
237 
238         any = daeSafeCast< domAny >(teq->getChild("Radius"));
239         if (any)
240         {
241             lod->setRadius(parseString<osg::LOD::value_type>(any->getValue()));
242         }
243         else
244         {
245             OSG_WARN << "Expected element 'Radius' not found" << std::endl;
246         }
247     }
248 
249     any = daeSafeCast< domAny >(teq->getChild("RangeMode"));
250     if (any)
251     {
252         lod->setRangeMode((osg::LOD::RangeMode)parseString<int>(any->getValue()));
253     }
254     else
255     {
256         OSG_WARN << "Expected element 'RangeMode' not found" << std::endl;
257     }
258 
259     any = daeSafeCast< domAny >(teq->getChild("RangeList"));
260     if (any)
261     {
262         osg::LOD::RangeList rangelist;
263 
264         unsigned int numChildren = any->getChildren().getCount();
265         for (unsigned int currChild = 0; currChild < numChildren; currChild++)
266         {
267             domAny* child = daeSafeCast<domAny>(any->getChildren()[currChild]);
268             if (child)
269             {
270                 if (strcmp(child->getElementName(), "MinMax" ) == 0 )
271                 {
272                     std::list<std::string> stringValues;
273                     osg::LOD::MinMaxPair minMaxPair;
274 
275                     cdom::tokenize(child->getValue(), " ", stringValues);
276                     cdom::tokenIter iter = stringValues.begin();
277 
278                     if (iter != stringValues.end())
279                     {
280                         minMaxPair.first = parseString<float>(*iter);
281                         ++iter;
282                     }
283                     else
284                     {
285                         OSG_WARN << "'MinMax' does not contain a valid minimum value" << std::endl;
286                     }
287 
288                     if (iter != stringValues.end())
289                     {
290                         minMaxPair.second = parseString<float>(*iter);
291                     }
292                     else
293                     {
294                         OSG_WARN << "'MinMax' does not contain a valid maximum value" << std::endl;
295                     }
296 
297                     rangelist.push_back(minMaxPair);
298                 }
299                 else
300                 {
301                     OSG_WARN << "Child of element 'RangeList' is not of type 'MinMax'" << std::endl;
302                 }
303             }
304             else
305             {
306                 OSG_WARN << "Element 'RangeList' does not contain expected elements." << std::endl;
307             }
308         }
309 
310         lod->setRangeList(rangelist);
311     }
312     else
313     {
314         OSG_WARN << "Expected element 'RangeList' not found" << std::endl;
315     }
316 
317     return lod;
318 }
319 
320 // <light>
321 // attributes:
322 // id, name
323 // elements:
324 // 0..1 <asset>
325 // 1    <technique_common>
326 //        1    <ambient>, <directional>, <point>, <spot>
327 // 0..* <technique>
328 // 0..* <extra>
processLight(domLight * dlight)329 osg::Node* daeReader::processLight( domLight *dlight )
330 {
331     if (_numlights >= 7)
332     {
333         OSG_WARN << "More than 8 lights may not be supported by OpenGL driver." << std::endl;
334     }
335 
336     //do light processing here.
337     domLight::domTechnique_common::domAmbient *ambient;
338     domLight::domTechnique_common::domDirectional *directional;
339     domLight::domTechnique_common::domPoint *point;
340     domLight::domTechnique_common::domSpot *spot;
341 
342     if ( dlight->getTechnique_common() == NULL ||
343          dlight->getTechnique_common()->getContents().getCount() == 0 )
344     {
345         OSG_WARN << "Invalid content for light" << std::endl;
346         return NULL;
347     }
348 
349     osg::Light* light = new osg::Light();
350     light->setPosition(osg::Vec4(0,0,0,1));
351     light->setLightNum(_numlights);
352 
353     // Enable OpenGL lighting
354     _rootStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
355     // Enable this OpenGL light
356     _rootStateSet->setMode(GL_LIGHT0 + _numlights++, osg::StateAttribute::ON);
357 
358     // Set ambient of lightmodel to zero
359     // Ambient lights are added as separate lights with only an ambient term
360     osg::LightModel* lightmodel = new osg::LightModel;
361     lightmodel->setAmbientIntensity(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
362     _rootStateSet->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
363 
364     osg::LightSource* lightsource = new osg::LightSource();
365     lightsource->setLight(light);
366     std::string name = dlight->getId() ? dlight->getId() : "";
367     if (dlight->getName())
368         name = dlight->getName();
369     lightsource->setName(name);
370 
371     daeElement *el = dlight->getTechnique_common()->getContents()[0];
372     ambient = daeSafeCast< domLight::domTechnique_common::domAmbient >( el );
373     directional = daeSafeCast< domLight::domTechnique_common::domDirectional >( el );
374     point = daeSafeCast< domLight::domTechnique_common::domPoint >( el );
375     spot = daeSafeCast< domLight::domTechnique_common::domSpot >( el );
376     if ( ambient != NULL )
377     {
378         if ( ambient->getColor() == NULL )
379         {
380             OSG_WARN << "Invalid content for ambient light" << std::endl;
381             return NULL;
382         }
383 
384         light->setAmbient(    osg::Vec4(    ambient->getColor()->getValue()[0],
385                                         ambient->getColor()->getValue()[1],
386                                         ambient->getColor()->getValue()[2], 1.0f ) );
387         light->setDiffuse(    osg::Vec4(    0, 0, 0, 0));
388         light->setSpecular(    osg::Vec4(    0, 0, 0, 0));
389 
390         // Tell OpenGL to make it a directional light (w=0)
391         light->setPosition(    osg::Vec4(0,0,0,0));
392     }
393     else if ( directional != NULL )
394     {
395         if ( directional->getColor() == NULL )
396         {
397             OSG_WARN << "Invalid content for directional light" << std::endl;
398             return NULL;
399         }
400         light->setAmbient(    osg::Vec4(    0, 0, 0, 0));
401         light->setDiffuse(    osg::Vec4(    directional->getColor()->getValue()[0],
402                                         directional->getColor()->getValue()[1],
403                                         directional->getColor()->getValue()[2], 1.0f ) );
404         light->setSpecular( osg::Vec4(    directional->getColor()->getValue()[0],
405                                         directional->getColor()->getValue()[1],
406                                         directional->getColor()->getValue()[2], 1.0f ) );
407 
408         light->setDirection(osg::Vec3(0,0,-1));
409 
410         // Tell OpenGL it is a directional light (w=0)
411         light->setPosition(    osg::Vec4(0,0,1,0));
412     }
413     else if ( point != NULL )
414     {
415         if ( point->getColor() == NULL )
416         {
417             OSG_WARN << "Invalid content for point light" << std::endl;
418             return NULL;
419         }
420         light->setAmbient(    osg::Vec4(    0, 0, 0, 0));
421         light->setDiffuse(    osg::Vec4(    point->getColor()->getValue()[0],
422                                         point->getColor()->getValue()[1],
423                                         point->getColor()->getValue()[2], 1.0f ) );
424         light->setSpecular( osg::Vec4(    point->getColor()->getValue()[0],
425                                         point->getColor()->getValue()[1],
426                                         point->getColor()->getValue()[2], 1.0f ) );
427 
428         if ( point->getConstant_attenuation() != NULL )
429         {
430             light->setConstantAttenuation( point->getConstant_attenuation()->getValue() );
431         }
432         else
433         {
434             light->setConstantAttenuation( 1.0 );
435         }
436         if ( point->getLinear_attenuation() != NULL )
437         {
438             light->setLinearAttenuation( point->getLinear_attenuation()->getValue() );
439         }
440         else
441         {
442             light->setLinearAttenuation( 0.0 );
443         }
444         if ( point->getQuadratic_attenuation() != NULL )
445         {
446             light->setQuadraticAttenuation( point->getQuadratic_attenuation()->getValue() );
447         }
448         else
449         {
450             light->setQuadraticAttenuation( 0.0 );
451         }
452 
453         // Tell OpenGL this is an omni directional light
454         light->setDirection(osg::Vec3(0, 0, 0));
455     }
456     else if ( spot != NULL )
457     {
458         if ( spot->getColor() == NULL )
459         {
460             OSG_WARN << "Invalid content for spot light" << std::endl;
461             return NULL;
462         }
463         light->setAmbient(    osg::Vec4(    0, 0, 0, 0));
464         light->setDiffuse(    osg::Vec4(    spot->getColor()->getValue()[0],
465                                         spot->getColor()->getValue()[1],
466                                         spot->getColor()->getValue()[2], 1.0f ) );
467         light->setSpecular( osg::Vec4(    spot->getColor()->getValue()[0],
468                                         spot->getColor()->getValue()[1],
469                                         spot->getColor()->getValue()[2], 1.0f ) );
470 
471         if ( spot->getConstant_attenuation() != NULL )
472         {
473             light->setConstantAttenuation( spot->getConstant_attenuation()->getValue() );
474         }
475         else
476         {
477             light->setConstantAttenuation( 1.0f );
478         }
479         if ( spot->getLinear_attenuation() != NULL )
480         {
481             light->setLinearAttenuation( spot->getLinear_attenuation()->getValue() );
482         }
483         else
484         {
485             light->setLinearAttenuation( 0.0f );
486         }
487         if ( spot->getQuadratic_attenuation() != NULL )
488         {
489             light->setQuadraticAttenuation( spot->getQuadratic_attenuation()->getValue() );
490         }
491         else
492         {
493             light->setQuadraticAttenuation( 0.0f );
494         }
495         // OpenGL range [0, 90] (degrees) or 180 (omni)
496         if ( spot->getFalloff_angle() != NULL )
497         {
498             float falloffAngle = spot->getFalloff_angle()->getValue();
499             if (falloffAngle != 180)
500             {
501                 falloffAngle = osg::clampTo<float>(falloffAngle, 0, 90);
502             }
503             light->setSpotCutoff(falloffAngle);
504         }
505         else
506         {
507             light->setSpotCutoff( 180.0f );
508         }
509         // OpenGL range [0, 128], where 0 means hard edge, and 128 means soft edge
510         if ( spot->getFalloff_exponent() != NULL )
511         {
512             float falloffExponent = spot->getFalloff_exponent()->getValue();
513             falloffExponent = osg::clampTo<float>(falloffExponent, 0, 128);
514             light->setSpotExponent(falloffExponent);
515         }
516         else
517         {
518             light->setSpotExponent( 0.0f );
519         }
520         light->setDirection(osg::Vec3(0, 0, -1));
521     }
522 
523     return lightsource;
524 }
525 
526 // <camera>
527 // attributes:
528 // id, name
529 // elements:
530 // 0..1 <asset>
531 // 1    <optics>
532 //        1       <technique_common>
533 //                1        <orthographic>, <perspective>
534 //        0..*    <technique>
535 //        0..*    <extra>
536 // 0..* <imager>
537 //        1       <technique>
538 //        0..*    <extra>
539 // 0..* <extra>
processCamera(domCamera * dcamera)540 osg::Node* daeReader::processCamera( domCamera * dcamera )
541 {
542     osg::CameraView* pOsgCameraView = new osg::CameraView;
543     pOsgCameraView->setName(dcamera->getId());
544 
545     domCamera::domOptics::domTechnique_common *pDomTechniqueCommon = dcamera->getOptics()->getTechnique_common();
546     domCamera::domOptics::domTechnique_common::domPerspective *pDomPerspective = pDomTechniqueCommon->getPerspective();
547     domCamera::domOptics::domTechnique_common::domOrthographic *pDomOrthographic = pDomTechniqueCommon->getOrthographic();
548     if (pDomPerspective)
549     {
550         // <perspective>
551         // 1    <xfov>, <yfov>, <xfov> and <yfov>, <xfov> and <aspect_ratio>, <yfov> and <aspect_ratio>
552         // 1    <znear>
553         // 1    <zfar>
554         domTargetableFloat *pXfov = daeSafeCast< domTargetableFloat >(pDomPerspective->getXfov());
555         domTargetableFloat *pYfov = daeSafeCast< domTargetableFloat >(pDomPerspective->getYfov());
556         domTargetableFloat *pAspectRatio = daeSafeCast< domTargetableFloat >(pDomPerspective->getAspect_ratio());
557 
558         if (pXfov)
559         {
560             if (pYfov)
561             {
562                 // <xfov> and <yfov>
563                 pOsgCameraView->setFieldOfView(pXfov->getValue());
564                 pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL);
565 
566                 if (pAspectRatio)
567                 {
568                     OSG_WARN << "Unexpected <aspectratio> in <camera> '" << dcamera->getId() << "'" << std::endl;
569                 }
570             }
571             else if (pAspectRatio)
572             {
573                 // <xfov> and <aspect_ratio>
574                 pOsgCameraView->setFieldOfView(pXfov->getValue() * pAspectRatio->getValue());
575                 pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL);
576             }
577             else
578             {
579                 // <xfov>
580                 pOsgCameraView->setFieldOfView(pXfov->getValue());
581                 pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL);
582             }
583         }
584         else if (pYfov)
585         {
586             if (pAspectRatio)
587             {
588                 // <yfov> and <aspect_ratio>
589                 pOsgCameraView->setFieldOfView(pYfov->getValue() / pAspectRatio->getValue());
590                 pOsgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL);
591             }
592             else
593             {
594                 // <yfov>
595                 pOsgCameraView->setFieldOfView(pYfov->getValue());
596                 pOsgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL);
597             }
598         }
599         else
600         {
601             // xfov or yfov expected
602             OSG_WARN << "Expected <xfov> or <yfov> in <camera> '" << dcamera->getId() << "'" << std::endl;
603         }
604 
605         //domTargetableFloat *pZnear = daeSafeCast< domTargetableFloat >(pDomPerspective->getZnear());
606         //domTargetableFloat *pZfar = daeSafeCast< domTargetableFloat >(pDomPerspective->getZfar());
607 
608         // TODO The current osg::CameraView does not support storage of near far
609     }
610     else if (pDomOrthographic)
611     {
612         // <orthographic>
613         // 1    <xmag>, <ymag>, <xmag> and <ymag>, <xmag> and <aspect_ratio>, <ymag> and <aspect_ratio>
614         // 1    <znear>
615         // 1    <zfar>
616 
617         //domTargetableFloat *pXmag = daeSafeCast< domTargetableFloat >(pDomOrthographic->getXmag());
618         //domTargetableFloat *pYmag = daeSafeCast< domTargetableFloat >(pDomOrthographic->getYmag());
619         //domTargetableFloat *pAspectRatio = daeSafeCast< domTargetableFloat >(pDomOrthographic->getAspect_ratio());
620 
621         // TODO The current osg::CameraView does not support an orthographic view
622         OSG_WARN << "Orthographic in <camera> '" << dcamera->getId() << "' not supported" << std::endl;
623 
624         //domTargetableFloat *pZnear = daeSafeCast< domTargetableFloat >(pDomOrthographic->getZnear());
625         //domTargetableFloat *pZfar = daeSafeCast< domTargetableFloat >(pDomOrthographic->getZfar());
626 
627         // TODO The current osg::CameraView does not support storage of near far
628     }
629 
630     return pOsgCameraView;
631 }
632