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 #ifndef _DAE_CONV_H_
15 #define _DAE_CONV_H_
16 
17 #include <string>
18 
19 #include <dae.h>
20 #include <dae/daeURI.h>
21 #include <dae/daeElement.h>
22 #include <dom/domCommon_color_or_texture_type.h>
23 #include <dom/domInputLocalOffset.h>
24 #include <dom/domInstance_controller.h>
25 
26 #include <osg/Node>
27 #include <osg/Notify>
28 #include <osgDB/ReaderWriter>
29 #include <osgDB/FileNameUtils>
30 #include <osgDB/FileUtils>
31 #include <osgDB/Registry>
32 #include <osg/Material>
33 #include <osg/Texture2D>
34 #include <osgAnimation/BasicAnimationManager>
35 #include <osgAnimation/Bone>
36 #include <osgAnimation/Skeleton>
37 
38 #ifdef COLLADA_DOM_2_4_OR_LATER
39 namespace ColladaDOM141
40 {
41 #endif
42 class domBind_material;
43 class domCamera;
44 //class domCommon_color_or_texture_type;
45 class domCommon_float_or_param_type;
46 class domGeometry;
47 class domInstance_controller;
48 class domInstance_geometry;
49 class domInstanceWithExtra;
50 class domLight;
51 class domLookat;
52 class domMatrix;
53 class domNode;
54 class domP;
55 class domProfile_COMMON;
56 class domScale;
57 class domSkew;
58 class domTranslate;
59 class domRotate;
60 class domVisual_scene;
61 
62 #ifdef COLLADA_DOM_2_4_OR_LATER
63 }
64 
65 using namespace ColladaDOM141;
66 #endif
67 
68 namespace osgDAE
69 {
70 
71 class domSourceReader;
72 
getElementFromURI(daeURI & uri)73 inline daeElement *getElementFromURI( daeURI &uri )
74 {
75     if ( uri.getState() == daeURI::uri_loaded || uri.getState() == daeURI::uri_pending ) {
76         uri.resolveElement();
77     }
78     return uri.getElement();
79 }
getElementFromIDRef(daeIDRef & idref)80 inline daeElement *getElementFromIDRef( daeIDRef &idref )
81 {
82     if ( idref.getState() == daeIDRef::id_loaded || idref.getState() == daeIDRef::id_pending ) {
83         idref.resolveElement();
84     }
85     return idref.getElement();
86 }
87 
88 template< typename TInputArray, typename TInputType >
89 bool findInputSourceBySemantic( TInputArray& inputs, const char* semantic, daeElement *& element,
90                                 TInputType ** input = NULL, int unit = 0 )
91 {
92     element = NULL;
93     int count = 0;
94     for ( size_t i = 0; i < inputs.getCount(); i++ ) {
95         if ( !strcmp(semantic, inputs[i]->getSemantic()) ) {
96             if ( count == unit )
97             {
98                 element = getElementFromURI( inputs[i]->getSource() );
99                 *input = (TInputType*)inputs[i];
100                 return true;
101             }
102             count++;
103         }
104     }
105     return false;
106 }
107 
108 /// Convert string to value using it's stream operator
109 template <typename T>
parseString(const std::string & valueAsString)110 T parseString(const std::string& valueAsString) {
111     std::stringstream str;
112     str << valueAsString;
113     T result;
114     str >> result;
115     return result;
116 }
117 
parseVec3String(const std::string & valueAsString)118 inline osg::Vec3 parseVec3String(const std::string& valueAsString)
119 {
120     std::stringstream str;
121     str << valueAsString;
122     osg::Vec3 result;
123     str >> result.x() >> result.y() >> result.z();
124     return result;
125 }
126 
parseMatrixString(const std::string & valueAsString)127 inline osg::Matrix parseMatrixString(const std::string& valueAsString)
128 {
129     std::stringstream str;
130     str << valueAsString;
131     osg::Matrix result;
132     str >> result(0,0) >> result(1,0) >> result(2,0) >> result(3,0)
133         >> result(0,1) >> result(1,1) >> result(2,1) >> result(3,1)
134         >> result(0,2) >> result(1,2) >> result(2,2) >> result(3,2)
135         >> result(0,3) >> result(1,3) >> result(2,3) >> result(3,3);
136     return result;
137 }
138 
139 
140 /**
141 @class daeReader
142 @brief Read a OSG scene from a DAE file
143 */
144 class daeReader {
145 public:
146     enum TessellateMode
147     {
148         TESSELLATE_NONE,                 ///< Do not tessellate at all (Polygons are stored as GL_POLYGON - not suitable for concave polygons)
149         TESSELLATE_POLYGONS_AS_TRIFAN,   ///< Tessellate the old way, interpreting polygons as triangle fans (faster, but does not work for concave polygons)
150         TESSELLATE_POLYGONS              ///< Use full tessellation of polygons (slower, works for concave polygons)
151     };
152 
153     struct Options
154     {
155         Options();
156         bool strictTransparency;
157         int precisionHint;              ///< Precision hint flags, as specified in osgDB::Options::PrecisionHint
158         bool usePredefinedTextureUnits;
159         TessellateMode tessellateMode;
160     };
161 
162     daeReader(DAE *dae_, const Options * pluginOptions);
163     virtual ~daeReader();
164 
165     bool convert( std::istream &fin );
166     bool convert( const std::string &fileURI );
167 
getRootNode()168     osg::Node* getRootNode()    { return _rootNode; }
169 
getAssetUnitName()170     const std::string& getAssetUnitName() const {return _assetUnitName;}
getAssetUnitMeter()171     float getAssetUnitMeter() const {return _assetUnitMeter;}
getAssetUpAxis()172     domUpAxisType getAssetUpAxis() const {return _assetUp_axis;}
173 
174     enum TextureUnitUsage
175     {
176         AMBIENT_OCCLUSION_UNIT = 0,
177         MAIN_TEXTURE_UNIT,
178         TRANSPARENCY_MAP_UNIT
179     };
180 
181     enum InterpolationType
182     {
183         INTERPOLATION_UNKNOWN,
184         INTERPOLATION_STEP,
185         INTERPOLATION_LINEAR,
186         INTERPOLATION_BEZIER,
187         INTERPOLATION_HERMITE,
188         INTERPOLATION_CARDINAL,
189         INTERPOLATION_BSPLINE,
190 
191         //COLLADA spec states that if interpolation is not specified then
192         //interpolation is application defined. Linear is a sensible default.
193         INTERPOLATION_DEFAULT = INTERPOLATION_LINEAR
194     };
195 
196     enum AuthoringTool
197     {
198         UNKNOWN,
199         BLENDER,
200         DAZ_STUDIO,
201         FBX_CONVERTER,
202         AUTODESK_3DS_MAX = FBX_CONVERTER,//3ds Max exports to DAE via Autodesk's FBX converter
203         GOOGLE_SKETCHUP,
204         MAYA
205     };
206 
207     class TextureParameters
208     {
209     public:
TextureParameters()210         TextureParameters()
211             : wrap_s(osg::Texture::REPEAT), wrap_t(osg::Texture::REPEAT),
212             filter_min(osg::Texture::LINEAR_MIPMAP_LINEAR), filter_mag(osg::Texture::LINEAR),
213             transparent(false), opaque(FX_OPAQUE_ENUM_A_ONE), transparency(1.0f)
214         {}
215 
216         bool operator < (const TextureParameters& rhs) const
217         {
218             int diffStr = filename.compare(rhs.filename);
219             if (diffStr) return diffStr < 0;
220             if (wrap_s != rhs.wrap_s) return wrap_s < rhs.wrap_s;
221             if (wrap_t != rhs.wrap_t) return wrap_t < rhs.wrap_t;
222             if (filter_min != rhs.filter_min) return filter_min < rhs.filter_min;
223             if (filter_mag != rhs.filter_mag) return filter_mag < rhs.filter_mag;
224             if (transparency != rhs.transparency) return transparency < rhs.transparency;
225             if (opaque != rhs.opaque) return opaque < rhs.opaque;
226             if (transparent != rhs.transparent) return transparent < rhs.transparent;
227             return border < rhs.border;
228         }
229 
230         std::string filename;
231         osg::Texture::WrapMode wrap_s, wrap_t;
232         osg::Texture::FilterMode filter_min, filter_mag;
233         osg::Vec4 border;
234 
235         //The following parameters are for transparency textures, to handle
236         //COLLADA's horrible transparency spec.
237         bool transparent;
238         domFx_opaque_enum opaque;
239         float transparency;
240     };
241 
242     class ChannelPart : public osg::Referenced
243     {
244     public:
245         std::string name;
246         osg::ref_ptr<osgAnimation::KeyframeContainer> keyframes;
247         InterpolationType interpolation;
248     };
249 
250     typedef std::map<domGeometry*, osg::ref_ptr<osg::Geode> >    domGeometryGeodeMap;
251     typedef std::map<domMaterial*, osg::ref_ptr<osg::StateSet> > domMaterialStateSetMap;
252     typedef std::map<std::string, osg::ref_ptr<osg::StateSet> >    MaterialStateSetMap;
253     typedef std::multimap< daeElement*, domChannel*> daeElementDomChannelMap;
254     typedef std::map<domChannel*, osg::ref_ptr<osg::Callback> > domChannelOsgAnimationUpdateCallbackMap;
255     typedef std::map<domNode*, osg::ref_ptr<osgAnimation::Bone> > domNodeOsgBoneMap;
256     typedef std::map<domNode*, osg::ref_ptr<osgAnimation::Skeleton> > domNodeOsgSkeletonMap;
257     typedef std::map<TextureParameters, osg::ref_ptr<osg::Texture2D> > TextureParametersMap;
258     typedef std::map<std::pair<const osg::StateSet*, TextureUnitUsage>, std::string> TextureToCoordSetMap;
259     typedef std::map<std::string, size_t> IdToCoordIndexMap;
260 
261     typedef std::map< daeElement*, domSourceReader > SourceMap;
262     typedef std::map< int, osg::IntArray*, std::less<int> > IndexMap;
263     typedef std::map< int, osg::Array*, std::less<int> > ArrayMap;
264 
265     typedef std::multimap< osgAnimation::Target*, osg::ref_ptr<ChannelPart> > TargetChannelPartMap;
266     typedef std::multimap<std::pair<const domMesh*, size_t>, std::pair<osg::ref_ptr<osg::Geometry>, GLuint> > OldToNewIndexMap;
267 
268 private:
269     bool processDocument( const std::string& );
270     void clearCaches();
271 
272     // If the node is a bone then it should be added before any other types of
273     // node, this function makes that happen.
274     static void addChild(osg::Group*, osg::Node*);
275 
276      //scene processing
277     osg::Group* turnZUp();
278     osg::Group*    processVisualScene( domVisual_scene *scene );
279     osg::Node*    processNode( domNode *node, bool skeleton );
280     osg::Transform*    processOsgMatrixTransform( domNode *node, bool isBone);
281 
282     template <typename T>
283     inline void getTransparencyCounts(daeDatabase*, int& zero, int& one) const;
284 
285     /** Earlier versions of the COLLADA 1.4 spec state that transparency values
286     of 0 mean 100% opacity, but this has been changed in later versions to state
287     that transparency values of 1 mean 100% opacity. Documents created by
288     different tools at different times adhere to different versions of the
289     standard. This function looks at all transparency values in the database and
290     heuristically decides which way the values should be interpreted.*/
291     bool findInvertTransparency(daeDatabase*) const;
292 
293     osgAnimation::BasicAnimationManager* processAnimationLibraries(domCOLLADA* document);
294     void processAnimationClip(osgAnimation::BasicAnimationManager* pOsgAnimationManager, domAnimation_clip* pDomAnimationClip);
295     void processAnimationMap(const TargetChannelPartMap&, osgAnimation::Animation* pOsgAnimation);
296     ChannelPart* processSampler(domChannel* pDomChannel, SourceMap &sources);
297     void processAnimationChannels(domAnimation* pDomAnimation, TargetChannelPartMap& tcm);
298     void processChannel(domChannel* pDomChannel, SourceMap &sources, TargetChannelPartMap& tcm);
299     void extractTargetName(const std::string&, std::string&, std::string&, std::string&);
300 
301     // Processing of OSG specific info stored in node extras
302     osg::Group* processExtras(domNode *node);
303     void processNodeExtra(osg::Node* osgNode, domNode *node);
304     domTechnique* getOpenSceneGraphProfile(domExtra* extra);
305     void processAsset( domAsset *node );
306 
307     osg::Group* processOsgSwitch(domTechnique* teq);
308     osg::Group* processOsgMultiSwitch(domTechnique* teq);
309     osg::Group* processOsgLOD(domTechnique* teq);
310     osg::Group* processOsgDOFTransform(domTechnique* teq);
311     osg::Group* processOsgSequence(domTechnique* teq);
312 
313     // geometry processing
314     osg::Geode* getOrCreateGeometry(domGeometry *geom, domBind_material* pDomBindMaterial, const osg::Geode** ppOriginalGeode = NULL);
315     osgAnimation::Bone* getOrCreateBone(domNode *pDomNode);
316     osgAnimation::Skeleton* getOrCreateSkeleton(domNode *pDomNode);
317     osg::Geode* processInstanceGeometry( domInstance_geometry *ig );
318 
319     osg::Geode* processMesh(domMesh* pDomMesh);
320     osg::Geode* processConvexMesh(domConvex_mesh* pDomConvexMesh);
321     osg::Geode* processSpline(domSpline* pDomSpline);
322     osg::Geode* processGeometry(domGeometry *pDomGeometry);
323 
324     typedef std::vector<domInstance_controller*> domInstance_controllerList;
325 
326     void processSkins();
327     //Process skins attached to one skeleton
328     void processSkeletonSkins(domNode* skeletonRoot, const domInstance_controllerList&);
329     void processSkin(domSkin* pDomSkin, domNode* skeletonRoot, osgAnimation::Skeleton*, domBind_material* pDomBindMaterial);
330     osg::Node* processMorph(domMorph* pDomMorph, domBind_material* pDomBindMaterial);
331     osg::Node* processInstanceController( domInstance_controller *ictrl );
332 
333     template< typename T >
334     void processSinglePPrimitive(osg::Geode* geode, const domMesh* pDomMesh, const T* group, SourceMap& sources, GLenum mode);
335 
336     template< typename T >
337     void processMultiPPrimitive(osg::Geode* geode, const domMesh* pDomMesh, const T* group, SourceMap& sources, GLenum mode);
338 
339     void processPolylist(osg::Geode* geode, const domMesh* pDomMesh, const domPolylist *group, SourceMap &sources, TessellateMode tessellateMode);
340 
341     template< typename T >
342     void processPolygons(osg::Geode* geode, const domMesh* pDomMesh, const T *group, SourceMap &sources, GLenum mode, TessellateMode tessellateMode);
343 
344     void resolveMeshArrays(const domP_Array&,
345         const domInputLocalOffset_Array& inputs, const domMesh* pDomMesh,
346         osg::Geometry* geometry, SourceMap &sources,
347         std::vector<std::vector<GLuint> >& vertexLists);
348 
349     //material/effect processing
350     void processBindMaterial( domBind_material *bm, domGeometry *geom, osg::Geode *geode, osg::Geode *cachedGeode );
351     void processMaterial(osg::StateSet *ss, domMaterial *mat );
352     void processEffect(osg::StateSet *ss, domEffect *effect );
353     void processProfileCOMMON(osg::StateSet *ss, domProfile_COMMON *pc );
354     bool processColorOrTextureType(const osg::StateSet*,
355                                     domCommon_color_or_texture_type *cot,
356                                     osg::Material::ColorMode channel,
357                                     osg::Material *mat,
358                                     domCommon_float_or_param_type *fop = NULL,
359                                     osg::Texture2D **sa = NULL,
360                                     bool normalizeShininess=false);
361     void processTransparencySettings( domCommon_transparent_type *ctt,
362                                         domCommon_float_or_param_type *pTransparency,
363                                         osg::StateSet*,
364                                         osg::Material *material,
365                                         unsigned int diffuseTextureUnit );
366     bool GetFloat4Param(xsNCName Reference, domFloat4 &f4) const;
367     bool GetFloatParam(xsNCName Reference, domFloat &f) const;
368 
369     std::string processImagePath(const domImage*) const;
370     osg::Image* processImageTransparency(const osg::Image*, domFx_opaque_enum, float transparency) const;
371     osg::Texture2D* processTexture( domCommon_color_or_texture_type_complexType::domTexture *tex, const osg::StateSet*, TextureUnitUsage, domFx_opaque_enum = FX_OPAQUE_ENUM_A_ONE, float transparency = 1.0f);
372     bool copyTextureCoordinateSet(const osg::StateSet* ss, const osg::Geometry* cachedGeometry, osg::Geometry* clonedGeometry, const domInstance_material* im, TextureUnitUsage tuu, unsigned int textureUnit);
373 
374     //scene objects
375     osg::Node* processLight( domLight *dlight );
376     osg::Node* processCamera( domCamera *dcamera );
377 
378     domNode* getRootJoint(domNode*) const;
379     domNode* findJointNode(daeElement* searchFrom, domInstance_controller*) const;
380     domNode* findSkeletonNode(daeElement* searchFrom, domInstance_controller*) const;
381 
382     /// Return whether the node is used as a bone. Note that while many files
383     /// identify joints with type="JOINT", some don't do this, while others
384     /// incorrectly identify every node as a joint.
isJoint(const domNode * node)385     bool isJoint(const domNode* node) const {return _jointSet.find(node) != _jointSet.end();}
386 
387 private:
388 
389     DAE *_dae;
390     osg::Node* _rootNode;
391     osg::ref_ptr<osg::StateSet> _rootStateSet;
392     domCOLLADA* _document;
393 
394     domVisual_scene* _visualScene;
395 
396     std::map<std::string,bool> _targetMap;
397 
398     int _numlights;
399 
400     domInstance_effect *_currentInstance_effect;
401     domEffect *_currentEffect;
402 
403     /// Maps an animated element to a domchannel to quickly find which animation influence this element
404     // TODO a single element can be animated by multiple channels (with different members like translate.x or morphweights(2) )
405     daeElementDomChannelMap _daeElementDomChannelMap;
406     /// Maps a domchannel to an animationupdatecallback
407     domChannelOsgAnimationUpdateCallbackMap _domChannelOsgAnimationUpdateCallbackMap;
408     /// Maps geometry to a Geode
409     domGeometryGeodeMap _geometryMap;
410     /// All nodes in the document that are used as joints.
411     std::set<const domNode*> _jointSet;
412     /// Maps a node (of type joint) to a osgAnimation::Bone
413     domNodeOsgBoneMap _jointMap;
414     /// Maps a node (of type joint) to a osgAnimation::Skeleton
415     domNodeOsgSkeletonMap _skeletonMap;
416     // Maps material target to stateset
417     domMaterialStateSetMap _materialMap;
418     // Maps material symbol to stateset
419     MaterialStateSetMap _materialMap2;
420     TextureParametersMap _textureParamMap;
421     TextureToCoordSetMap _texCoordSetMap;
422     IdToCoordIndexMap    _texCoordIdMap;
423     domInstance_controllerList _skinInstanceControllers;
424     OldToNewIndexMap _oldToNewIndexMap;
425 
426     AuthoringTool _authoringTool;
427     bool _invertTransparency;
428     Options _pluginOptions;
429 
430     // Additional Information
431     std::string _assetUnitName;
432     float _assetUnitMeter;
433     domUpAxisType _assetUp_axis;
434 };
435 
436 }
437 
438 #endif
439 
440 
441