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_WRITER_H_
15 #define _DAE_WRITER_H_
16 
17 #include <map>
18 #include <stack>
19 
20 #include <osg/Node>
21 #include <osg/Geode>
22 #include <osg/Geometry>
23 #include <osg/Group>
24 #include <osg/LightSource>
25 #include <osg/Camera>
26 #include <osg/Material>
27 #include <osg/MatrixTransform>
28 #include <osg/PositionAttitudeTransform>
29 #include <osg/Switch>
30 #include <osg/StateSet>
31 #include <osg/LOD>
32 #include <osg/ProxyNode>
33 #include <osg/CoordinateSystemNode>
34 #include <osg/BlendColor>
35 #include <osg/BlendFunc>
36 
37 #include <osg/Notify>
38 #include <osg/NodeVisitor>
39 #include <osgDB/FileNameUtils>
40 #include <osgDB/FileUtils>
41 #include <osgDB/Registry>
42 #include <osgDB/ExternalFileWriter>
43 #include <osgSim/MultiSwitch>
44 #include <osgAnimation/AnimationManagerBase>
45 #include <osgAnimation/UpdateBone>
46 #include <osgAnimation/RigGeometry>
47 #include <osgAnimation/MorphGeometry>
48 
49 #include <dae.h>
50 #include <dae/daeDocument.h>
51 #include <dom/domChannel.h>
52 
53 #ifdef COLLADA_DOM_2_4_OR_LATER
54 namespace ColladaDOM141
55 {
56 #endif
57 
58 class domCOLLADA;
59 class domGeometry;
60 class domInstance_geometry;
61 class domLibrary_cameras;
62 class domLibrary_effects;
63 class domLibrary_geometries;
64 class domLibrary_lights;
65 class domLibrary_materials;
66 class domLibrary_visual_scenes;
67 class domLibrary_animations;
68 class domMaterial;
69 class domMesh;
70 class domNode;
71 class domSource;
72 class domVisual_scene;
73 class domP;
74 
75 #ifdef COLLADA_DOM_2_4_OR_LATER
76 }
77 
78 using namespace ColladaDOM141;
79 #endif
80 
81 namespace osgDAE {
82 
83 /// Convert value to string using it's stream operator
84 template <typename T>
toString(T value)85 std::string toString(T value)
86 {
87     std::stringstream str;
88     str << value;
89     return str.str();
90 }
91 
92 std::string toString(const osg::Vec3f& value);
93 std::string toString(const osg::Vec3d& value);
94 std::string toString(const osg::Matrix& value);
95 
96 // Collects all nodes that are targeted by an animation
97 class FindAnimatedNodeVisitor : public osg::NodeVisitor
98 {
99 public:
FindAnimatedNodeVisitor()100     FindAnimatedNodeVisitor():
101         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
102         {}
103 
apply(osg::Node & node)104     virtual void apply(osg::Node& node)
105     {
106         osg::Callback* ncb = node.getUpdateCallback();
107         if (ncb)
108         {
109             osgAnimation::AnimationUpdateCallback<osg::NodeCallback>* ut = dynamic_cast<osgAnimation::AnimationUpdateCallback<osg::NodeCallback>*>(ncb);
110             if (ut)
111             {
112                 if (_updateCallbackNameNodeMap[ut->getName()] == NULL)
113                 {
114                     _updateCallbackNameNodeMap[ut->getName()] = &node;
115                 }
116                 else
117                 {
118                     // TODO store in a multimap and let the exporter create multiple <channel>s for each connected node
119                     OSG_WARN << "Multiple nodes using the same update callback not supported" << std::endl;
120                 }
121             }
122         }
123         traverse(node);
124     }
125 
getTargetNode(const std::string & targetName)126     osg::Node* getTargetNode(const std::string& targetName)
127     {
128         UpdateCallbackNameNodeMap::iterator it = _updateCallbackNameNodeMap.find(targetName);
129         if (it != _updateCallbackNameNodeMap.end())
130         {
131             return it->second;
132         }
133         return NULL;
134     }
135 
136 private:
137     typedef std::map< std::string, osg::Node*>    UpdateCallbackNameNodeMap;
138     UpdateCallbackNameNodeMap _updateCallbackNameNodeMap;
139 };
140 
141 /**
142 @class daeWriter
143 @brief Write a OSG scene into a DAE file
144 */
145 class daeWriter : public osg::NodeVisitor
146 {
147 protected:
148     class ArrayNIndices;
149 public:
150     struct Options
151     {
152         Options();
153 
154         bool usePolygons;
155         /** work in Google compatibility mode. In daeWMaterials, change transparency color. And in daeWGeometry, replace tristrip and trifans by triangles*/
156         bool googleMode;
157         /** Write OSG specific data as extra data. */
158         bool writeExtras;
159         /** work in Google compatibility mode for textures*/
160         bool earthTex;
161         /** link to original images instead of exporting */
162         bool linkOrignialTextures;
163         /** force the use an image for a texture, even if the file is not found (when m_linkOrignialTextures). */
164         bool forceTexture;
165         bool namesUseCodepage;
166         unsigned int relativiseImagesPathNbUpDirs;
167     };
168     daeWriter(DAE *dae_, const std::string &fileURI, const std::string & directory, const std::string & srcDirectory, const osgDB::ReaderWriter::Options * options, TraversalMode tm=TRAVERSE_ALL_CHILDREN, const Options * pluginOptions=NULL);
169     virtual ~daeWriter();
170 
171     void setRootNode( const osg::Node &node );
172 
isSuccess()173     bool isSuccess() { return success; }
174 
175     bool writeFile();
176 
177     virtual void    apply( osg::Node &node );
178     virtual void    apply( osg::Geode &node );
179     virtual void    apply( osg::Group &node );
180     virtual void    apply( osg::LightSource &node );
181     virtual void    apply( osg::Camera &node );
182     virtual void    apply( osg::MatrixTransform &node );
183     virtual void    apply( osg::PositionAttitudeTransform &node );
184     virtual void    apply( osg::Switch &node );
185     virtual void    apply( osg::Sequence &node );
186     virtual void    apply( osg::LOD &node );
187 
188     //virtual void    apply( osg::Billboard &node);
189     virtual void    apply( osg::ProxyNode &node );
190     //virtual void  apply( osg::Projection &node)
191     virtual void    apply( osg::CoordinateSystemNode &node );
192     //virtual void  apply( osg::ClipNode &node)
193     //virtual void  apply( osg::TexGenNode &node)
194     virtual void    apply( osg::Transform &node );
195     virtual void    apply( osg::CameraView &node);
196     //virtual void  apply( osg::PagedLOD &node)
197     //virtual void  apply( osg::ClearNode &node)
198     //virtual void  apply( osg::OccluderNode &node)
199 
200     void traverse (osg::Node &node);
201 
202 
203 
204 
205 protected: //methods
206 
207     void writeAnimations(osg::Node& node);
208     void writeNodeExtra(osg::Node &node);
209     void writeUpdateTransformElements(const osg::Vec3 &pos, const osg::Quat &q,    const osg::Vec3 &s);
210     void writeRigGeometry(osgAnimation::RigGeometry *pOsgRigGeometry);
211     void writeMorphGeometry(osgAnimation::MorphGeometry *pOsgMorphGeometry);
212 
213     void debugPrint( osg::Node &node );
214 
215     domGeometry* getOrCreateDomGeometry(osg::Geometry* pOsgGeometry);
216     bool processGeometry( osg::Geometry *geom, domGeometry *geo, const std::string &name );
217     domSource* createSource( daeElement *parent, const std::string &baseName, int size, bool color = false, bool uv = false );
218     template < typename Ty >
219         Ty *createPrimGroup( daeString type, domMesh *mesh, domSource *norm, domSource *color, const std::vector< domSource* > &texcoord );
220 
221     void processMaterial( osg::StateSet *ss, domBind_material *pDomBindMaterial, const std::string &geoName );
222 
223     void createAssetTag(bool isZUpAxis);
224 
225     // Overloaded version of createAssetTag which provides ability to
226     // set user defined values for child elements
227     void createAssetTag(const osg::Node &node);
228 
229     void pushStateSet(osg::StateSet* ss);
230 
231     void popStateSet(osg::StateSet* ss);
232 
233 protected: //members
234     DAE *dae;
235     daeDocument *doc;
236     domCOLLADA *dom;
237     domLibrary_cameras *lib_cameras;
238     domLibrary_effects *lib_effects;
239     domLibrary_controllers *lib_controllers;
240     domLibrary_geometries *lib_geoms;
241     domLibrary_lights *lib_lights;
242     domLibrary_materials *lib_mats;
243     domLibrary_visual_scenes *lib_vis_scenes;
244     domLibrary_animations* _domLibraryAnimations;
245     domNode *currentNode;
246     domVisual_scene *vs;
247 
248     bool success;
249     unsigned int lastDepth;
250 
251   struct CompareStateSet
252   {
operatorCompareStateSet253       bool operator()(const osg::ref_ptr<osg::StateSet>& ss1, const osg::ref_ptr<osg::StateSet>& ss2) const
254     {
255       //std::cout << "CompareStateSet: " << ss1->compare(*ss2, false) << " " << ss1 << " " << ss2 << std::endl;
256       return ss1->compare(*ss2, true) < 0;
257     }
258   };
259 
260 
261     typedef std::map< osg::ref_ptr<osg::StateSet>, domMaterial *, CompareStateSet> MaterialMap;
262     typedef std::stack<osg::ref_ptr<osg::StateSet> > StateSetStack;
263     typedef std::map< osg::Geometry*, domGeometry *> OsgGeometryDomGeometryMap;
264     typedef std::map< osgAnimation::RigGeometry*, domController *> OsgRigGeometryDomControllerMap;
265     typedef std::map< osgAnimation::MorphGeometry*, domController *> OsgMorphGeometryDomControllerMap;
266 
267     std::map< std::string, int > uniqueNames;
268     OsgGeometryDomGeometryMap geometryMap;
269     OsgRigGeometryDomControllerMap _osgRigGeometryDomControllerMap;
270     OsgMorphGeometryDomControllerMap _osgMorphGeometryDomControllerMap;
271 
272     MaterialMap materialMap;
273     StateSetStack stateSetStack;
274 
275     osg::ref_ptr<osg::StateSet> currentStateSet;
276 
277     daeURI rootName;
278 
279     osg::StateSet* CleanStateSet(osg::StateSet* pStateSet) const;
280 
281     void updateCurrentDaeNode();
282 
283 protected: //inner classes
284     class ArrayNIndices
285     {
286     public:
287         enum Mode { NONE, VEC2F, VEC2D, VEC3F, VEC3D, VEC4F, VEC4D, VEC4_UB };
288 
289         osg::Vec2Array*         vec2;
290         osg::Vec3Array*         vec3;
291         osg::Vec4Array*         vec4;
292         osg::Vec2dArray*        vec2d;
293         osg::Vec3dArray*        vec3d;
294         osg::Vec4dArray*        vec4d;
295         osg::Vec4ubArray*       vec4ub;
296 
297         osg::Array*             valArray;
298         osg::IndexArray*        inds;
299 
300         ArrayNIndices( osg::Array* valArray, osg::IndexArray* ind );
301 
getMode()302         Mode getMode() const { return mode; }
303 
304         unsigned int getDAESize();
305 
306         /// Appends the contained OSG vector array to a domListOfFloats
307         bool append(domListOfFloats & list);
308     protected:
309         Mode mode;
310     };
311 
312 private: //members
313 
314         /** append elements (verts, normals, colors and texcoord) for file write */
315         void appendGeometryIndices(osg::Geometry *geom,
316                                           domP * p,
317                                           unsigned int vindex,
318                                           domSource * norm,
319                                           domSource * color,
320                                           const ArrayNIndices & verts,
321                                           const ArrayNIndices & normals,
322                                           const ArrayNIndices & colors,
323                                           const std::vector<ArrayNIndices> & texcoords,
324                                           unsigned int  ncount,
325                                           unsigned int  ccount);
326 
327         /** provide a name to node */
328         std::string getNodeName(const osg::Node & node,const std::string & defaultName);
329 
330         /** provide an unique name */
331         std::string uniquify( const std::string &name );
332 
333         /** Current RenderingHint */
334         /** This are needed because the stateSet merge code currently does not handle it */
335         int m_CurrentRenderingHint;
336 
337         FindAnimatedNodeVisitor _animatedNodeCollector;
338 
339         const osgDB::ReaderWriter::Options * _options;
340         Options _pluginOptions;
341         osgDB::ExternalFileWriter _externalWriter;
342 };
343 
344 }
345 
346 #endif
347 
348