/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSGDB_PLUGIN_IMAGE_WRITER #define OSGDB_PLUGIN_IMAGE_WRITER 1 #include #include #include namespace osg { class Object; } namespace osgDB { class Options; /// Helper allowing 'intelligent' writing of external files (images, shaders, etc.), regarding to a main file (a scene), especially in plugins. /// Goals are: /// - Enable writing out objects only once (even if referenced multiple times) /// - Handle duplicates (avoid writing two different objects at the same place, renaming files as needed) /// - Handle directory creation when paths don't just exist /// - Generate writing paths which may keep original directory structure (depending on user wishes). Ex: /// Reading: model.osg and images/img1.jpg /// Writing with 'keepRelativePaths': /somePath/newmodel.osg and /somePath/images/img1.jpg /// Writing without 'keepRelativePaths': /somePath/newmodel.osg and /somePath/img1.jpg ///\author Sukender ///\todo Handling of naming constraints (such as "8.3" names in 3DS) class OSGDB_EXPORT ExternalFileWriter { public: /// Builds the helper class with all options. ///\param srcDirectory Directory of the initial main file (if any), used as a base when relativising objects names. Not used if keepRelativePaths==false. ///\param destDirectory Directory where to write the main file. ///\param keepRelativePaths If true, then relative paths of source objects are kept if possible (ex: If an image is initially "imageDir/image.jpg" relatively to the source dir, then we'd like to get "destDir/imageDir/image.jpg"). If false, then only the simple file name is used to write the object file. ///\param allowUpDirs When relativising objects paths, sets the maximum number of directories the objects can be written "up" the destination directory. Not used if keepRelativePaths==false. Examples: If an image is initially "../image.jpg" relatively to the source dir *AND* if we allow one dir level up, then we'd like to get "destDirParent/destDir/../image.jpg" (= "destDirParent/image.jpg"). If we *DO NOT* allow one dir level up, then we'd like to get "destDir/image.jpg". ExternalFileWriter(const std::string & srcDirectory, const std::string & destDirectory, bool keepRelativePaths, unsigned int allowUpDirs=0); /// Short constructor used when not relativising objects paths, or when having no initial model file (which is pretty the same here). ExternalFileWriter(const std::string & destDirectory); /// Writes the current object if not already done. ///\param obj Object to write, using corresponding osgDB::write method. ///\param options Writing options to pass to corresponding osgDB::write method. ///\param [out] out_absolutePath Pointer to a string to be filled with absolute writing path, or NULL. ///\param [out] out_relativePath Pointer to a string to be filled with write path relative to the destination directory if possible (absolute path if not), or NULL. ///\return true on success, false otherwise. bool write(const osg::Object & obj, const osgDB::Options * options, std::string * out_absolutePath=NULL, std::string * out_relativePath=NULL); struct ObjectData { ObjectData() : written(false) {} ObjectData(const std::string & in_absolutePath, const std::string & in_relativePath, bool in_written) : absolutePath(in_absolutePath), relativePath(in_relativePath), written(in_written) {} std::string absolutePath; std::string relativePath; bool written; ///< Says if write succeeded or not. }; /// Set of written objects, with their absolute writing path. /// Objects being passed to the write() method but which have failed to be effectively written are also included. typedef std::map ObjectsSet; /// Returns the written objects. const ObjectsSet & getObjects() const { return _objects; } protected: // Dev note: // A multi-indexed structure would be more efficient for ObjectsSet (such as boost::multi_index, indexed on object pointer (unique), and hashed indexed on absolute path (unique)). // In order to get a correct search time, SearchMap "replaces" the multi-index structure for hashed indexes on absolute paths. typedef std::multimap SearchMap; typedef unsigned int ObjectIndex; ///< Integer type used for indices of unnamed objects ObjectsSet _objects; SearchMap _searchMap; ///< Map used to search by absolute file path. ObjectIndex _lastGeneratedObjectIndex; const std::string _srcDirectory; const std::string _destDirectory; bool _keepRelativePaths; const unsigned int _allowUpDirs; /// Generates a unique name for an object to be written on disk. /// Side effect: updates _lastGeneratedObjectIndex to the index associated with the returned name. void generateObjectName(std::string & out_relativePath, std::string & out_absolutePath, int type); bool absoluteObjectPathExists(const std::string & path); private: // Prevent copy ExternalFileWriter & operator=(const ExternalFileWriter &); ExternalFileWriter(const ExternalFileWriter &); }; } #endif // OSGDB_PLUGIN_IMAGE_WRITER