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