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 "domSourceReader.h"
16 #include <dae.h>
17 #include <dom/domCOLLADA.h>
18 #include <dom/domInstance_geometry.h>
19 #include <dom/domInstance_controller.h>
20 #include <dom/domController.h>
21 #include <dom/domConstants.h>
22 #include <osg/StateSet>
23 #include <osg/ShapeDrawable>
24 #include <osg/Geometry>
25 
26 #include <osgUtil/Tessellator>
27 
28 #include <osgAnimation/MorphGeometry>
29 #include <osgAnimation/RigGeometry>
30 #include <osgAnimation/UpdateBone>
31 
32 using namespace osgDAE;
33 
getOrCreateGeometry(domGeometry * pDomGeometry,domBind_material * pDomBindMaterial,const osg::Geode ** ppOriginalGeode)34 osg::Geode* daeReader::getOrCreateGeometry(domGeometry *pDomGeometry, domBind_material* pDomBindMaterial, const osg::Geode** ppOriginalGeode)
35 {
36     // Check cache if geometry already exists
37     osg::Geode* pOsgGeode;
38 
39     domGeometryGeodeMap::iterator iter = _geometryMap.find( pDomGeometry );
40     if ( iter != _geometryMap.end() )
41     {
42         pOsgGeode = iter->second.get();
43     }
44     else
45     {
46         pOsgGeode = processGeometry( pDomGeometry );
47         _geometryMap.insert( std::make_pair( pDomGeometry, pOsgGeode ) );
48     }
49 
50     if (ppOriginalGeode)
51     {
52         *ppOriginalGeode = pOsgGeode;
53     }
54 
55     if (!pOsgGeode)
56         return NULL;
57 
58     // Create a copy of the cached Geode with a copy of the drawables,
59     // because we may be using a different material or texture unit bindings.
60     osg::Geode *pCopiedOsgGeode = static_cast<osg::Geode*>(pOsgGeode->clone(osg::CopyOp::DEEP_COPY_DRAWABLES));
61     if ( pCopiedOsgGeode == NULL )
62     {
63         OSG_WARN << "Failed to load geometry " << pDomGeometry->getName() << std::endl;
64         return NULL;
65     }
66 
67     // Compute optimized geometry by expanding all indexed arrays so we are no longer rendering with the slow path
68     for(unsigned int i=0;i < pCopiedOsgGeode->getNumDrawables();++i)
69     {
70         osg::Geometry* geom = pCopiedOsgGeode->getDrawable(i)->asGeometry();
71         if (geom)
72         {
73             if (geom->containsDeprecatedData())
74             {
75                 geom->fixDeprecatedData();
76             }
77         }
78     }
79 
80     if (pDomBindMaterial)
81     {
82         processBindMaterial( pDomBindMaterial, pDomGeometry, pCopiedOsgGeode, pOsgGeode );
83     }
84 
85     return pCopiedOsgGeode;
86 }
87 
getOrCreateBone(domNode * pDomNode)88 osgAnimation::Bone* daeReader::getOrCreateBone(domNode *pDomNode)
89 {
90     // Check cache if bone already exists
91     osgAnimation::Bone *pOsgBone = NULL;
92 
93     domNodeOsgBoneMap::iterator iterBone = _jointMap.find( pDomNode );
94     if ( iterBone != _jointMap.end() )
95         return iterBone->second.get();
96 
97     std::string name;
98     if (pDomNode->getId())
99         name = pDomNode->getId();
100     if (name.empty() && pDomNode->getSid())
101         name = pDomNode->getSid();
102     if (name.empty() && pDomNode->getName())
103         name = pDomNode->getName();
104     pOsgBone = new osgAnimation::Bone(name);
105     pOsgBone->setDataVariance(osg::Object::DYNAMIC);
106 
107     pOsgBone->setUpdateCallback(new osgAnimation::UpdateBone(name));
108 
109     _jointMap.insert( std::make_pair( pDomNode, pOsgBone ) );
110 
111     return pOsgBone;
112 }
113 
getOrCreateSkeleton(domNode * pDomNode)114 osgAnimation::Skeleton* daeReader::getOrCreateSkeleton(domNode *pDomNode)
115 {
116     // Check cache if skeleton already exists
117     osgAnimation::Skeleton *pOsgSkeleton = NULL;
118 
119     domNodeOsgSkeletonMap::iterator iter = _skeletonMap.find( pDomNode );
120     if ( iter != _skeletonMap.end() )
121         return iter->second.get();
122 
123     pOsgSkeleton = new osgAnimation::Skeleton;
124     pOsgSkeleton->setDefaultUpdateCallback();
125     pOsgSkeleton->setDataVariance(osg::Object::DYNAMIC);
126 
127     _skeletonMap.insert( std::make_pair( pDomNode, pOsgSkeleton ) );
128 
129     return pOsgSkeleton;
130 }
131 
132 
133 
processInstanceGeometry(domInstance_geometry * pDomInstanceGeometry)134 osg::Geode* daeReader::processInstanceGeometry( domInstance_geometry *pDomInstanceGeometry )
135 {
136     domGeometry *pDomGeometry = daeSafeCast< domGeometry >(getElementFromURI(pDomInstanceGeometry->getUrl()));
137     if (!pDomGeometry)
138     {
139         OSG_WARN << "Failed to locate geometry " << pDomInstanceGeometry->getUrl().getURI() << std::endl;
140         return NULL;
141     }
142 
143     return getOrCreateGeometry(pDomGeometry, pDomInstanceGeometry->getBind_material());
144 }
145 
146 // <morph source (method)>
147 // 2..*    <source>
148 // 1    <targets>
149 //        2..*    <input semantic source>
150 //        0..*    <extra>
151 // 0..* <extra>
processMorph(domMorph * pDomMorph,domBind_material * pDomBindMaterial)152 osg::Node* daeReader::processMorph(domMorph* pDomMorph, domBind_material* pDomBindMaterial)
153 {
154     domGeometry* pDomGeometry = daeSafeCast< domGeometry >(getElementFromURI( pDomMorph->getSource()));
155 
156     if (!pDomGeometry)
157     {
158         OSG_WARN << "Failed to locate geometry " << pDomMorph->getSource().getURI() << std::endl;
159         return NULL;
160     }
161 
162     // Base mesh
163     osg::Geode* pOsgGeode = getOrCreateGeometry(pDomGeometry, pDomBindMaterial);
164     if (!pOsgGeode)
165         return NULL;
166 
167     // Expects a single geometry inside the geode, should change this
168     osg::Geometry* pOsgGeometry = dynamic_cast<osg::Geometry*>(pOsgGeode->getDrawable(0));
169     if (!pOsgGeometry)
170         return NULL;
171 
172     osgAnimation::MorphGeometry* pOsgMorphGeometry = new osgAnimation::MorphGeometry(*pOsgGeometry);
173     pOsgGeode->removeDrawables(0);
174     pOsgGeode->addDrawable(pOsgMorphGeometry);
175 
176     domMorphMethodType morphMethod = pDomMorph->getMethod();
177 
178     //Files exported by the FBX converter always seem to say they're relative
179     //when in fact they should be normalized.
180     if (_authoringTool == FBX_CONVERTER)
181     {
182         morphMethod = MORPHMETHODTYPE_NORMALIZED;
183     }
184 
185     switch (morphMethod)
186     {
187     case MORPHMETHODTYPE_RELATIVE:
188         pOsgMorphGeometry->setMethod(osgAnimation::MorphGeometry::RELATIVE);
189         break;
190     case MORPHMETHODTYPE_NORMALIZED:
191         pOsgMorphGeometry->setMethod(osgAnimation::MorphGeometry::NORMALIZED);
192         break;
193     default:
194         OSG_WARN << "Unknown morph method method type " << std::endl;
195     }
196 
197     // 1    <targets>
198     domMorph::domTargets* pDomMorhpTargets = pDomMorph->getTargets();
199     domInputLocal_Array domInputs = pDomMorhpTargets->getInput_array();
200 
201     // TODO how to handle multiple pairs of morph inputs?
202     if (domInputs.getCount() > 2)
203     {
204         OSG_WARN << "Only a single pair of morph inputs is supported." << std::endl;
205     }
206 
207     for (size_t i=0; i < 2; i++)
208     {
209         if (!strcmp(domInputs[i]->getSemantic(), COMMON_PROFILE_INPUT_MORPH_TARGET))
210         {
211             domSource* pDomSource = daeSafeCast<domSource>(getElementFromURI(domInputs[i]->getSource()));
212             if (pDomSource)
213             {
214                 if (const domName_array* pDomNames = pDomSource->getName_array())
215                 {
216                     const domListOfNames& names = pDomNames->getValue();
217                     for (size_t j=0; j < names.getCount(); j++)
218                     {
219                         daeSIDResolver resolver(_visualScene, names.get(j));
220                         pDomGeometry = daeSafeCast< domGeometry >(resolver.getElement());
221 
222                         if (pDomGeometry)
223                         {
224                             osg::Geode* targetgeode = getOrCreateGeometry(pDomGeometry, NULL);
225 
226                             // Expects a single geometry inside the geode, should change this
227                             osg::Geometry* pOsgGeometry = dynamic_cast<osg::Geometry*>(targetgeode->getDrawable(0));
228                             if (pOsgGeometry)
229                             {
230                                 pOsgMorphGeometry->addMorphTarget(pOsgGeometry);
231                             }
232                         }
233                         else
234                         {
235                             OSG_WARN << "Failed to locate morph geometry '" << names.get(j) << "'" << std::endl;
236                         }
237                     }
238                 }
239                 else if (domIDREF_array* pDomIDREFs = pDomSource->getIDREF_array())
240                 {
241                     xsIDREFS* pIDREFS = &(pDomIDREFs->getValue());
242                     for (size_t j=0; j < pIDREFS->getCount(); j++)
243                     {
244                         pDomGeometry = daeSafeCast< domGeometry >(getElementFromIDRef(pIDREFS->get(j)));
245 
246                         if (pDomGeometry)
247                         {
248                             osg::Geode* targetgeode = getOrCreateGeometry(pDomGeometry, NULL);
249 
250                             // Expects a single geometry inside the geode, should change this
251                             osg::Geometry* pOsgGeometry = dynamic_cast<osg::Geometry*>(targetgeode->getDrawable(0));
252                             if (pOsgGeometry)
253                             {
254                                 pOsgMorphGeometry->addMorphTarget(pOsgGeometry);
255                             }
256                         }
257                         else
258                         {
259                             OSG_WARN << "Failed to locate morph geometry '" << pIDREFS->get(j).getID() << "'" << std::endl;
260                         }
261                     }
262                 }
263             }
264             else
265             {
266                 OSG_WARN << "Could not find morph source '" << domInputs[i]->getSource().getURI() << "'" <<std::endl;
267                 return NULL;
268             }
269         }
270         else if (!strcmp(domInputs[i]->getSemantic(), COMMON_PROFILE_INPUT_MORPH_WEIGHT))
271         {
272             domSource* pDomSource = daeSafeCast<domSource>(getElementFromURI(domInputs[i]->getSource()));
273             if (pDomSource)
274             {
275                 domFloat_array* pDomFloatArray = pDomSource->getFloat_array();
276                 domListOfFloats weights = pDomFloatArray->getValue();
277                 for (size_t j=0; j < pDomFloatArray->getCount(); j++)
278                 {
279                     pOsgMorphGeometry->setWeight(j, weights.get(j));
280                 }
281 
282                 // See if morph weights are targeted by animations
283                 daeElementDomChannelMap::iterator iter = _daeElementDomChannelMap.find(pDomSource);
284                 if (iter != _daeElementDomChannelMap.end())
285                 {
286                     std::string name = pDomSource->getId() ? pDomSource->getId() : "";
287                     osgAnimation::UpdateMorph* pUpdateCallback = new osgAnimation::UpdateMorph(name);
288                     pOsgGeode->setUpdateCallback(pUpdateCallback);
289                     pOsgGeode->setDataVariance(osg::Object::DYNAMIC);
290 
291                     // Associate all animation channels with this update callback
292                     do
293                     {
294                         _domChannelOsgAnimationUpdateCallbackMap[iter->second] = pUpdateCallback;
295                         ++iter;
296                     }
297                     while (iter != _daeElementDomChannelMap.upper_bound(pDomSource));
298                 }
299             }
300             else
301             {
302                 OSG_WARN << "Could not find morph source '" << domInputs[i]->getSource().getURI() << "'" <<std::endl;
303                 return NULL;
304             }
305         }
306     }
307 
308     return pOsgGeode;
309 }
310 
311 // <controller (id) (name)>
312 // 0..1 <asset>
313 // 1    <skin>, <morph>
314 // 0..* <extra>
processInstanceController(domInstance_controller * pDomInstanceController)315 osg::Node* daeReader::processInstanceController( domInstance_controller *pDomInstanceController )
316 {
317     domController *pDomController = daeSafeCast< domController >(getElementFromURI(pDomInstanceController->getUrl()));
318     if (!pDomController)
319     {
320         OSG_WARN << "Failed to locate controller " << pDomInstanceController->getUrl().getURI() << std::endl;
321         return NULL;
322     }
323 
324     if (pDomController->getSkin())
325     {
326         _skinInstanceControllers.push_back(pDomInstanceController);
327         return NULL;
328     }
329     else if (pDomController->getMorph())
330     {
331         return processMorph(pDomController->getMorph(), pDomInstanceController->getBind_material());
332     }
333 
334     OSG_WARN << "Expected skin or morph element in controller '" << pDomController->getName() << "'" << std::endl;
335 
336     return NULL;
337 }
338 
339 // <mesh>
340 // 1..* <source>
341 // 1    <vertices>
342 // 0..*    <lines>, <linestrips>, <polygons>, <polylist>, <triangles>, <trifans>, <tristrips>
343 // 0..* <extra>
processMesh(domMesh * pDomMesh)344 osg::Geode *daeReader::processMesh(domMesh* pDomMesh)
345 {
346     osg::Geode* pOsgGeode = new osg::Geode;
347 //    if (pDomMesh->getId() != NULL )
348     {
349 //        pOsgGeode->setName( pDomMesh->getId() );
350     }
351 
352     // size_t count = mesh->getContents().getCount();
353 
354     // 1..* <source>
355     SourceMap sources;
356     domSource_Array sourceArray = pDomMesh->getSource_array();
357     for ( size_t i = 0; i < sourceArray.getCount(); i++)
358     {
359         sources.insert(std::make_pair((daeElement*)sourceArray[i], domSourceReader(sourceArray[i])));
360     }
361 
362     // 0..*    <lines>
363     domLines_Array linesArray = pDomMesh->getLines_array();
364     for ( size_t i = 0; i < linesArray.getCount(); i++)
365     {
366         processSinglePPrimitive<domLines>(pOsgGeode, pDomMesh, linesArray[i], sources, GL_LINES);
367     }
368 
369     // 0..*    <linestrips>
370     domLinestrips_Array linestripsArray = pDomMesh->getLinestrips_array();
371     for ( size_t i = 0; i < linestripsArray.getCount(); i++)
372     {
373         processMultiPPrimitive<domLinestrips>(pOsgGeode, pDomMesh, linestripsArray[i], sources, GL_LINE_STRIP);
374     }
375 
376     // 0..* <polygons>
377     domPolygons_Array polygonsArray = pDomMesh->getPolygons_array();
378     for ( size_t i = 0; i < polygonsArray.getCount(); i++)
379     {
380         processPolygons<domPolygons>(pOsgGeode, pDomMesh, polygonsArray[i], sources, GL_POLYGON, _pluginOptions.tessellateMode);
381     }
382 
383     // 0..* <polylist>
384     domPolylist_Array polylistArray = pDomMesh->getPolylist_array();
385     for ( size_t i = 0; i < polylistArray.getCount(); i++)
386     {
387         processPolylist(pOsgGeode, pDomMesh, polylistArray[i], sources, _pluginOptions.tessellateMode);
388     }
389 
390     // 0..* <triangles>
391     domTriangles_Array trianglesArray = pDomMesh->getTriangles_array();
392     for ( size_t i = 0; i < trianglesArray.getCount(); i++)
393     {
394         processSinglePPrimitive<domTriangles>(pOsgGeode, pDomMesh, trianglesArray[i], sources, GL_TRIANGLES);
395     }
396 
397     // 0..* <trifans>
398     domTrifans_Array trifansArray = pDomMesh->getTrifans_array();
399     for ( size_t i = 0; i < trifansArray.getCount(); i++)
400     {
401         processPolygons<domTrifans>(pOsgGeode, pDomMesh, trifansArray[i], sources, GL_TRIANGLE_FAN, TESSELLATE_NONE);
402     }
403 
404     // 0..* <tristrips>
405     domTristrips_Array tristripsArray = pDomMesh->getTristrips_array();
406     for ( size_t i = 0; i < tristripsArray.getCount(); i++)
407     {
408         processMultiPPrimitive<domTristrips>(pOsgGeode, pDomMesh, tristripsArray[i], sources, GL_TRIANGLE_STRIP);
409     }
410 
411     return pOsgGeode;
412 }
413 
414 // <convexmesh>
processConvexMesh(domConvex_mesh * pDomConvexMesh)415 osg::Geode *daeReader::processConvexMesh(domConvex_mesh* pDomConvexMesh)
416 {
417 //    OSG_WARN << "Unsupported geometry convex mesh '" << pDomConvexMesh->getId() << "'" << std::endl;
418     return NULL;
419 }
420 
421 // <spline>
processSpline(domSpline * pDomSpline)422 osg::Geode *daeReader::processSpline(domSpline* pDomSpline)
423 {
424 //    OSG_WARN << "Unsupported geometry type spline '" << pDomSpline->getId() << "'" << std::endl;
425     return NULL;
426 }
427 
428 // <geometry (id) (name)>
429 // 0..1 <asset>
430 // 1    <convex_mesh>, <mesh>, <spline>
431 // 0..* <extra>
processGeometry(domGeometry * pDomGeometry)432 osg::Geode *daeReader::processGeometry(domGeometry *pDomGeometry)
433 {
434     if (pDomGeometry->getMesh())
435     {
436         return processMesh(pDomGeometry->getMesh());
437     }
438     else if (pDomGeometry->getConvex_mesh())
439     {
440         return processConvexMesh(pDomGeometry->getConvex_mesh());
441     }
442     else if (pDomGeometry->getSpline())
443     {
444         return processSpline(pDomGeometry->getSpline());
445     }
446 #ifdef COLLADA15
447     else if (pDomGeometry->getBRep())
448     {
449         return processBRep(pDomGeometry->getBRep());
450     }
451 #endif
452 
453     OSG_WARN << "Unexpected geometry type in geometry '" << pDomGeometry->getId() << "'" << std::endl;
454     return NULL;
455 }
456 
457 
458 template< typename T >
processSinglePPrimitive(osg::Geode * geode,const domMesh * pDomMesh,const T * group,SourceMap & sources,GLenum mode)459 void daeReader::processSinglePPrimitive(osg::Geode* geode,
460     const domMesh* pDomMesh, const T* group, SourceMap& sources, GLenum mode)
461 {
462     osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
463     if (NULL != group->getMaterial())
464         geometry->setName(group->getMaterial());
465 
466 
467     osg::ref_ptr<osg::DrawElementsUInt> pDrawElements = new osg::DrawElementsUInt(mode);
468     geometry->addPrimitiveSet(pDrawElements.get());
469 
470     domP_Array domPArray;
471     domPArray.append(group->getP());
472     std::vector<std::vector<GLuint> > indexLists;
473     resolveMeshArrays(domPArray, group->getInput_array(), pDomMesh, geometry.get(), sources, indexLists);
474     if (!indexLists.front().empty())
475     {
476         pDrawElements->asVector().swap(indexLists.front());
477         geode->addDrawable( geometry.get() );
478     }
479 }
480 
481 template< typename T >
processMultiPPrimitive(osg::Geode * geode,const domMesh * pDomMesh,const T * group,SourceMap & sources,GLenum mode)482 void daeReader::processMultiPPrimitive(osg::Geode* geode,
483     const domMesh* pDomMesh, const T* group, SourceMap &sources, GLenum mode)
484 {
485     osg::Geometry *geometry = new osg::Geometry();
486     if (NULL != group->getMaterial())
487         geometry->setName(group->getMaterial());
488     geode->addDrawable( geometry );
489 
490     std::vector<std::vector<GLuint> > indexLists;
491     resolveMeshArrays(group->getP_array(), group->getInput_array(), pDomMesh,
492         geometry, sources, indexLists);
493 
494     for (size_t i = 0; i < indexLists.size(); ++i)
495     {
496         osg::DrawElementsUInt* pDrawElements = new osg::DrawElementsUInt(mode);
497         geometry->addPrimitiveSet(pDrawElements);
498         pDrawElements->asVector().swap(indexLists[i]);
499     }
500 }
501 
processPolylist(osg::Geode * geode,const domMesh * pDomMesh,const domPolylist * group,SourceMap & sources,TessellateMode tessellateMode)502 void daeReader::processPolylist(osg::Geode* geode, const domMesh* pDomMesh, const domPolylist *group, SourceMap &sources, TessellateMode tessellateMode)
503 {
504     const domPolylist::domVcount* pDomVcount = group->getVcount();
505     if (!pDomVcount)
506     {
507         OSG_WARN << "Index counts not found." << std::endl;
508         return;
509     }
510 
511     osg::Geometry* geometry = new osg::Geometry();
512     if (NULL != group->getMaterial())
513         geometry->setName(group->getMaterial());
514     geode->addDrawable(geometry);
515 
516     std::vector<std::vector<GLuint> > vertexLists;
517     domP_Array domPArray;
518     domPArray.append(group->getP());
519     resolveMeshArrays(domPArray, group->getInput_array(), pDomMesh, geometry, sources, vertexLists);
520 
521     const std::vector<GLuint>& vertexList = vertexLists.front();
522 
523     osg::DrawElementsUInt* pDrawTriangles(NULL);
524     if (tessellateMode == TESSELLATE_POLYGONS_AS_TRIFAN)
525     {
526         // Produce triangles, interpreting polygons as fans (old way)
527         pDrawTriangles = new osg::DrawElementsUInt(GL_TRIANGLES);
528         geometry->addPrimitiveSet(pDrawTriangles);
529 
530         const domListOfUInts& vCount = pDomVcount->getValue();
531         for (size_t i = 0, j = 0; i < vCount.getCount(); ++i)
532         {
533             size_t primitiveLength = vCount[i];
534             if (j + primitiveLength > vertexList.size())
535             {
536                 OSG_WARN << "Error: vertex counts are greater than the number of indices." << std::endl;
537                 return;
538             }
539             for (size_t k = 2; k < primitiveLength; ++k)
540             {
541                 pDrawTriangles->push_back(vertexList[j]);
542                 pDrawTriangles->push_back(vertexList[j+k-1]);
543                 pDrawTriangles->push_back(vertexList[j+k]);
544             }
545             j += primitiveLength;
546         }
547     }
548     else
549     {
550         // Produce polygons or well-tessellated polygons
551         const domListOfUInts& vCount = pDomVcount->getValue();
552         for (size_t i = 0, j = 0; i < vCount.getCount(); ++i)
553         {
554             size_t primitiveLength = vCount[i];
555             if (j + primitiveLength > vertexList.size())
556             {
557                 OSG_WARN << "Error: vertex counts are greater than the number of indices." << std::endl;
558                 return;
559             }
560 
561             osg::DrawElementsUInt* pDrawElements = new osg::DrawElementsUInt(GL_POLYGON);
562             geometry->addPrimitiveSet(pDrawElements);
563             for (size_t k = 0; k < primitiveLength; ++k)
564             {
565                 pDrawElements->push_back(vertexList[k+j]);
566             }
567 
568             j += primitiveLength;
569         }
570 
571         if (tessellateMode == TESSELLATE_POLYGONS)
572         {
573             osgUtil::Tessellator tessellator;
574             tessellator.setTessellationType(osgUtil::Tessellator::TESS_TYPE_POLYGONS);
575             tessellator.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
576             tessellator.retessellatePolygons(*geometry);
577         }
578     }
579 }
580 
581 template< typename T >
processPolygons(osg::Geode * geode,const domMesh * pDomMesh,const T * group,SourceMap & sources,GLenum mode,TessellateMode tessellateMode)582 void daeReader::processPolygons(osg::Geode* geode,
583     const domMesh* pDomMesh, const T *group, SourceMap& sources, GLenum mode, TessellateMode tessellateMode)
584 {
585     osg::Geometry *geometry = new osg::Geometry();
586     geometry->setName(group->getMaterial());
587     geode->addDrawable(geometry);
588 
589     std::vector<std::vector<GLuint> > indexLists;
590     resolveMeshArrays(group->getP_array(), group->getInput_array(), pDomMesh,
591         geometry, sources, indexLists);
592 
593     if (tessellateMode == TESSELLATE_POLYGONS_AS_TRIFAN)
594     {
595         // Produce triangles, interpreting polygons as fans (old way)
596         osg::DrawElementsUInt* pDrawElements = new osg::DrawElementsUInt(GL_TRIANGLES);
597         geometry->addPrimitiveSet(pDrawElements);
598 
599         std::vector<std::vector<GLuint> > indexLists;
600         resolveMeshArrays(group->getP_array(), group->getInput_array(), pDomMesh,
601             geometry, sources, indexLists);
602 
603         for ( size_t i = 0; i < indexLists.size(); ++i)
604         {
605             const std::vector<GLuint>& indices = indexLists[i];
606 
607             for (size_t j = 2; j < indices.size(); ++j)
608             {
609                 pDrawElements->push_back(indices.front());
610                 pDrawElements->push_back(indices[j - 1]);
611                 pDrawElements->push_back(indices[j]);
612             }
613         }
614     }
615     else
616     {
617         // Produce polygons or well-tessellated polygons
618         for ( size_t i = 0; i < indexLists.size(); ++i)
619         {
620             const std::vector<GLuint>& indices = indexLists[i];
621 
622             osg::DrawElementsUInt* pDrawElements = new osg::DrawElementsUInt(mode);
623             geometry->addPrimitiveSet(pDrawElements);
624             for (size_t j = 0; j < indices.size(); ++j)
625             {
626                 pDrawElements->push_back(indices[j]);
627             }
628         }
629 
630         if (tessellateMode == TESSELLATE_POLYGONS)
631         {
632             osgUtil::Tessellator tessellator;
633             tessellator.setTessellationType(osgUtil::Tessellator::TESS_TYPE_POLYGONS);
634             tessellator.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
635             tessellator.retessellatePolygons(*geometry);
636         }
637     }
638 }
639 
processVertices(domVertices * vertices,daeElement * & position_source,daeElement * & color_source,daeElement * & normal_source,daeElement * & texcoord_source)640 void processVertices(
641     domVertices* vertices,
642     daeElement*& position_source,
643     daeElement*& color_source,
644     daeElement*& normal_source,
645     daeElement*& texcoord_source)
646 {
647     const domInputLocal_Array& inputs = vertices->getInput_array();
648 
649     // Process input elements within the vertices element. These are of the unshared type
650     // and therefore cannot have set and offset attributes
651 
652     for (size_t i = 0; i < inputs.getCount(); ++i)
653     {
654         xsNMTOKEN semantic = inputs[i]->getSemantic();
655         daeElement* pDaeElement = getElementFromURI(inputs[i]->getSource());
656         if (strcmp(COMMON_PROFILE_INPUT_POSITION, semantic) == 0)
657         {
658             position_source = pDaeElement;
659         }
660         else if (strcmp(COMMON_PROFILE_INPUT_COLOR, semantic) == 0)
661         {
662             color_source = pDaeElement;
663         }
664         else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, semantic) == 0)
665         {
666             normal_source = pDaeElement;
667         }
668         else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, semantic) == 0)
669         {
670             texcoord_source = pDaeElement;
671         }
672     }
673 }
674 
675 // I've never seen more than 2 used so this should be enough. If you find that
676 // a greater number is needed then increase it accordingly and submit the change
677 // to OpenSceneGraph.
678 // Why not use a vector? Because a large map of VertexIndices is used and
679 // allocating vectors for each element would make it a lot slower.
680 const unsigned int MAX_TEXTURE_COORDINATE_SETS = 4;
681 
resolveMeshInputs(const domInputLocalOffset_Array & inputs,daeElement * & position_source,daeElement * & color_source,daeElement * & normal_source,daeElement * texcoord_sources[MAX_TEXTURE_COORDINATE_SETS],int & position_offset,int & color_offset,int & normal_offset,int texcoord_offsets[MAX_TEXTURE_COORDINATE_SETS])682 void resolveMeshInputs(
683     const domInputLocalOffset_Array &inputs,
684     daeElement*& position_source,
685     daeElement*& color_source,
686     daeElement*& normal_source,
687     daeElement* texcoord_sources[MAX_TEXTURE_COORDINATE_SETS],
688     int& position_offset,
689     int& color_offset,
690     int& normal_offset,
691     int texcoord_offsets[MAX_TEXTURE_COORDINATE_SETS])
692 {
693     position_source = color_source = normal_source = NULL;
694     position_offset = color_offset = normal_offset = 0;
695     for (unsigned int i = 0; i < MAX_TEXTURE_COORDINATE_SETS; ++i)
696     {
697         texcoord_sources[i] = NULL;
698         texcoord_offsets[i] = 0;
699     }
700 
701     for ( size_t i = 0; i < inputs.getCount(); i++ )
702     {
703         if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0)
704         {
705             daeElement* pDaeElement = getElementFromURI(inputs[i]->getSource());
706             if (domVertices* vertices = daeSafeCast<domVertices>(pDaeElement))
707             {
708                 processVertices(vertices, position_source, color_source, normal_source, texcoord_sources[0]);
709                 position_offset = inputs[i]->getOffset();
710 
711                 if (color_source) color_offset = position_offset;
712                 if (normal_source) normal_offset = position_offset;
713                 if (texcoord_sources[0]) texcoord_offsets[0] = position_offset;
714             }
715             break;
716         }
717     }
718 
719     for ( size_t i = 0; i < inputs.getCount(); i++ )
720     {
721         xsNMTOKEN semantic = inputs[i]->getSemantic();
722         daeElement* pDaeElement = getElementFromURI(inputs[i]->getSource());
723         int offset = inputs[i]->getOffset();
724 
725         if (strcmp(COMMON_PROFILE_INPUT_COLOR, semantic) == 0)
726         {
727             if (color_source != NULL)
728                 OSG_WARN<<"Overwriting vertices input(COLOR) with input from primitive"<<std::endl;
729             color_source = pDaeElement;
730             color_offset = offset;
731         }
732         else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, semantic) == 0)
733         {
734             if (normal_source != NULL)
735                 OSG_WARN<<"Overwriting vertices input(NORMAL) with input from primitive"<<std::endl;
736             normal_source = pDaeElement;
737             normal_offset = offset;
738         }
739         else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, semantic) == 0)
740         {
741             unsigned set = inputs[i]->getSet();
742             if (set >= MAX_TEXTURE_COORDINATE_SETS)
743             {
744                 OSG_WARN<<"Texture coordinate set "<< set <<
745                     "was requested, the maximum allowed is " << MAX_TEXTURE_COORDINATE_SETS - 1 << "." << std::endl;
746                 continue;
747             }
748             if (texcoord_sources[set])
749                 OSG_WARN<<"Overwriting vertices input(TEXCOORD) with input from primitive"<<std::endl;
750 
751             texcoord_sources[set] = pDaeElement;
752             texcoord_offsets[set] = offset;
753         }
754     }
755 }
756 
757 struct VertexIndices
758 {
VertexIndicesVertexIndices759     VertexIndices(int p, int c, int n, const int t[MAX_TEXTURE_COORDINATE_SETS])
760         : position_index(p), color_index(c), normal_index(n)
761     {
762         for (unsigned int i = 0; i < MAX_TEXTURE_COORDINATE_SETS; ++i) texcoord_indices[i] = t[i];
763     }
operator <VertexIndices764     bool operator < (const VertexIndices& rhs) const
765     {
766         if (position_index != rhs.position_index) return position_index < rhs.position_index;
767         if (color_index != rhs.color_index) return color_index < rhs.color_index;
768         if (normal_index != rhs.normal_index) return normal_index < rhs.normal_index;
769         for (unsigned int i = 0; i < MAX_TEXTURE_COORDINATE_SETS; ++i)
770         {
771             if (texcoord_indices[i] != rhs.texcoord_indices[i]) return texcoord_indices[i] < rhs.texcoord_indices[i];
772         }
773         return false;
774     }
775 
776     /// Templated getter for memebers, used for createGeometryArray()
777     enum ValueType { POSITION, COLOR, NORMAL, TEXCOORD };
778     template <int Value>
779     inline int get() const;
780 
781     int position_index, color_index, normal_index, texcoord_indices[MAX_TEXTURE_COORDINATE_SETS];
782 };
783 
784 template<>
get() const785 inline int VertexIndices::get<VertexIndices::POSITION>() const { return position_index; }
786 template<>
get() const787 inline int VertexIndices::get<VertexIndices::COLOR>() const { return color_index; }
788 template<>
get() const789 inline int VertexIndices::get<VertexIndices::NORMAL>() const { return normal_index; }
790 template<int Value>
get() const791 inline int VertexIndices::get() const {
792     // TEXCOORD has not to be implemented here as we need compile-time constants for texcoord number
793     return -1;
794 }
795 
796 
797 typedef std::map<VertexIndices, GLuint> VertexIndicesIndexMap;
798 
799 /// Creates a value array, packed in a osg::Array, corresponding to indexed values.
800 template <class ArrayType, int Value>
801 ArrayType* createGeometryArray(domSourceReader & sourceReader, const VertexIndicesIndexMap & vertexIndicesIndexMap, int texcoordNum=-1) {
802     const ArrayType * source = sourceReader.getArray<ArrayType>();
803     if (!source) return 0;
804     ArrayType * pArray = new ArrayType(osg::Array::BIND_PER_VERTEX);
805     for (VertexIndicesIndexMap::const_iterator it = vertexIndicesIndexMap.begin(), end = vertexIndicesIndexMap.end(); it != end; ++it) {
806         int index = texcoordNum>=0 ? it->first.texcoord_indices[texcoordNum] : it->first.get<Value>();
807         if (index>=0 && static_cast<unsigned int>(index)<source->size()) pArray->push_back(source->at(index));
808         else {
809             // Invalid data (index out of bounds)
810             //LOG_WARN << ...
811             //pArray->push_back(0);
812             return 0;
813         }
814     }
815     return pArray;
816 }
817 
818 
819 template <class ArrayTypeSingle, class ArrayTypeDouble, int Value>
createGeometryArray(domSourceReader & sourceReader,const VertexIndicesIndexMap & vertexIndicesIndexMap,bool useDoublePrecision,int texcoordNum=-1)820 inline osg::Array* createGeometryArray(domSourceReader & sourceReader, const VertexIndicesIndexMap & vertexIndicesIndexMap, bool useDoublePrecision, int texcoordNum=-1) {
821     if (useDoublePrecision) return createGeometryArray<ArrayTypeDouble, Value>(sourceReader, vertexIndicesIndexMap, texcoordNum);
822     else                    return createGeometryArray<ArrayTypeSingle, Value>(sourceReader, vertexIndicesIndexMap, texcoordNum);
823 }
824 
825 
resolveMeshArrays(const domP_Array & domPArray,const domInputLocalOffset_Array & inputs,const domMesh * pDomMesh,osg::Geometry * geometry,SourceMap & sources,std::vector<std::vector<GLuint>> & vertexLists)826 void daeReader::resolveMeshArrays(const domP_Array& domPArray,
827     const domInputLocalOffset_Array& inputs, const domMesh* pDomMesh,
828     osg::Geometry* geometry, SourceMap &sources,
829     std::vector<std::vector<GLuint> >& vertexLists)
830 {
831     daeElement* position_source = NULL;
832     daeElement* color_source = NULL;
833     daeElement* normal_source = NULL;
834     daeElement* texcoord_sources[MAX_TEXTURE_COORDINATE_SETS] = {NULL};
835     int position_offset = 0;
836     int color_offset = 0;
837     int normal_offset = 0;
838     int texcoord_offsets[MAX_TEXTURE_COORDINATE_SETS] = {0};
839 
840     resolveMeshInputs(inputs,
841         position_source,
842         color_source,
843         normal_source,
844         texcoord_sources,
845         position_offset,
846         color_offset,
847         normal_offset,
848         texcoord_offsets);
849 
850     unsigned stride = 0;
851     for (size_t i = 0; i < inputs.getCount(); ++i)
852     {
853         stride = osg::maximum<unsigned>(stride, inputs[i]->getOffset());
854     }
855     ++stride;
856 
857     VertexIndicesIndexMap vertexIndicesIndexMap;
858 
859     for (size_t j = 0; j < domPArray.getCount(); ++j)
860     {
861         const domListOfUInts& p = domPArray[j]->getValue();
862 
863         for (size_t i = 0; i < p.getCount(); i += stride)
864         {
865             int texcoord_indices[MAX_TEXTURE_COORDINATE_SETS];
866             for (unsigned int t = 0; t < MAX_TEXTURE_COORDINATE_SETS; ++t)
867             {
868                 texcoord_indices[t] = p.get(i + texcoord_offsets[t]);
869             }
870             VertexIndices v(
871                 p.get(i + position_offset),
872                 p.get(i + color_offset),
873                 p.get(i + normal_offset),
874                 texcoord_indices);
875             vertexIndicesIndexMap.insert(VertexIndicesIndexMap::value_type(v, 0));
876         }
877     }
878 
879     {
880         VertexIndicesIndexMap::iterator it = vertexIndicesIndexMap.begin(), end = vertexIndicesIndexMap.end();
881         for (GLuint i = 0; it != end; ++it, ++i)
882         {
883             it->second = i;
884         }
885     }
886 
887     vertexLists.resize(domPArray.getCount());
888 
889     for (size_t j = 0; j < domPArray.getCount(); ++j)
890     {
891         const domListOfUInts& p = domPArray[j]->getValue();
892 
893         for (size_t i = 0; i < p.getCount(); i += stride)
894         {
895             int texcoord_indices[MAX_TEXTURE_COORDINATE_SETS];
896             for (unsigned int t = 0; t < MAX_TEXTURE_COORDINATE_SETS; ++t)
897             {
898                 texcoord_indices[t] = p.get(i + texcoord_offsets[t]);
899             }
900             VertexIndices v(
901                 p.get(i + position_offset),
902                 p.get(i + color_offset),
903                 p.get(i + normal_offset),
904                 texcoord_indices);
905 
906             GLuint index = vertexIndicesIndexMap.find(v)->second;
907 
908             _oldToNewIndexMap.insert(OldToNewIndexMap::value_type(
909                 OldToNewIndexMap::key_type(pDomMesh, v.position_index),
910                 OldToNewIndexMap::mapped_type(geometry, index)));
911             vertexLists[j].push_back(index);
912         }
913     }
914 
915     const bool readDoubleVertices  = (_pluginOptions.precisionHint & osgDB::Options::DOUBLE_PRECISION_VERTEX) != 0;
916     const bool readDoubleColors    = (_pluginOptions.precisionHint & osgDB::Options::DOUBLE_PRECISION_COLOR) != 0;
917     const bool readDoubleNormals   = (_pluginOptions.precisionHint & osgDB::Options::DOUBLE_PRECISION_NORMAL) != 0;
918     const bool readDoubleTexcoords = (_pluginOptions.precisionHint & osgDB::Options::DOUBLE_PRECISION_TEX_COORD) != 0;
919 
920     // Vertices
921     {
922         osg::ref_ptr<osg::Array> array( createGeometryArray<osg::Vec3Array, osg::Vec3dArray, VertexIndices::POSITION>(sources[position_source], vertexIndicesIndexMap, readDoubleVertices) );
923         if (array.valid())
924         {
925             geometry->setVertexArray(array.get());
926         }
927     }
928 
929     if (color_source)
930     {
931         // first try Vec4Array
932         osg::ref_ptr<osg::Array> array( createGeometryArray<osg::Vec4Array, osg::Vec4dArray, VertexIndices::COLOR>(sources[color_source], vertexIndicesIndexMap, readDoubleColors) );
933 
934         // if no array matched try Vec3Array
935         if (!array)
936         {
937             array = createGeometryArray<osg::Vec3Array, osg::Vec3dArray, VertexIndices::COLOR>(sources[color_source], vertexIndicesIndexMap, readDoubleColors);
938         }
939 
940         if (array.valid())
941         {
942             geometry->setColorArray(array.get());
943         }
944     }
945 
946     if (normal_source)
947     {
948         osg::ref_ptr<osg::Array> array( createGeometryArray<osg::Vec3Array, osg::Vec3dArray, VertexIndices::NORMAL>(sources[normal_source], vertexIndicesIndexMap, readDoubleNormals) );
949         if (array.valid())
950         {
951             geometry->setNormalArray(array.get());
952         }
953     }
954 
955     for (unsigned int texcoord_set = 0; texcoord_set < MAX_TEXTURE_COORDINATE_SETS; ++texcoord_set)
956     {
957         if (daeElement* texcoord_source = texcoord_sources[texcoord_set])
958         {
959             std::string id = std::string("#") + texcoord_source->getID();
960             //We keep somewhere the mapping between daeElement id and created arrays
961             _texCoordIdMap.insert(std::pair<std::string,size_t>(id,texcoord_set));
962             // 2D Texcoords
963             osg::ref_ptr<osg::Array> array( createGeometryArray<osg::Vec2Array, osg::Vec2dArray, VertexIndices::TEXCOORD>(sources[texcoord_source], vertexIndicesIndexMap, readDoubleTexcoords, texcoord_set) );
964             if (array.valid())
965             {
966                 geometry->setTexCoordArray(texcoord_set, array.get());
967             }
968             else
969             {
970                 // 3D Textcoords
971                 osg::ref_ptr<osg::Array> array( createGeometryArray<osg::Vec3Array, osg::Vec3dArray, VertexIndices::TEXCOORD>(sources[texcoord_source], vertexIndicesIndexMap, readDoubleTexcoords, texcoord_set) );
972                 if (array.valid())
973                 {
974                     geometry->setTexCoordArray(texcoord_set, array.get());
975                 }
976             }
977         }
978     }
979 }
980