// -*-c++-*- /* * 3DS reader/writer for Open Scene Graph * * Copyright (C) ??? * * Writing support added 2007 by Sukender (Benoit Neil), http://sukender.free.fr, * strongly inspired by the OBJ writer object by Stephan Huber * * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for * real-time rendering of large 3D photo-realistic models. * The OSG homepage is http://www.openscenegraph.org/ */ #ifndef _3DS_WRITER_NODE_VISITOR_HEADER__ #define _3DS_WRITER_NODE_VISITOR_HEADER__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lib3ds/lib3ds.h" #include "WriterCompareTriangle.h" void copyOsgMatrixToLib3dsMatrix(Lib3dsMatrix lib3ds_matrix, const osg::Matrix& osg_matrix); typedef std::map, unsigned int> MapIndices; typedef std::vector > ListTriangle; //the int is the drawable of the triangle class WriterNodeVisitor: public osg::NodeVisitor { public: static const unsigned int MAX_VERTICES = 65000; static const unsigned int MAX_FACES = MAX_VERTICES; WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName, const osgDB::ReaderWriter::Options* options, const std::string & srcDirectory) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _suceedLastApply(true), _srcDirectory(srcDirectory), file3ds(file3ds), _currentStateSet(new osg::StateSet()), _lastGeneratedNumberedName(0), _lastMaterialIndex(0), _lastMeshIndex(0), _cur3dsNode(NULL), options(options), _imageCount(0) { //supportsOption("flipTexture", "flip texture upside-down"); if (!fileName.empty()) _directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front(); } bool suceedLastApply() const; void failedApply(); virtual void apply(osg::Geode &node); virtual void apply(osg::Group &node); virtual void apply(osg::MatrixTransform &node); void traverse (osg::Node &node) { pushStateSet(node.getStateSet()); osg::NodeVisitor::traverse( node ); popStateSet(node.getStateSet()); } void pushStateSet(osg::StateSet* ss) { if (NULL!=ss) { // Save our current stateset _stateSetStack.push(_currentStateSet.get()); // merge with node stateset _currentStateSet = static_cast(_currentStateSet->clone(osg::CopyOp::SHALLOW_COPY)); _currentStateSet->merge(*ss); } } void popStateSet(osg::StateSet* ss) { if (NULL!=ss) { // restore the previous stateset _currentStateSet = _stateSetStack.top(); _stateSetStack.pop(); } } void writeMaterials(); ///\todo Add support for 2nd texture, opacity_map, bump_map, specular_map, shininess_map, self_illum_map, reflection_map. class Material { public: Material(WriterNodeVisitor & writerNodeVisitor, osg::StateSet * stateset, osg::Material* mat, osg::Texture* tex, int index=-1); int index; ///< Index in the 3DS file osg::Vec4 diffuse, ambient, specular; float shininess; float transparency; bool double_sided; std::string name; osg::ref_ptr image; bool texture_transparency; bool texture_no_tile; protected: Material() : index(-1) {} }; protected: struct CompareStateSet { bool operator()(const osg::ref_ptr& ss1, const osg::ref_ptr& ss2) const { return *ss1 < *ss2; } }; private: WriterNodeVisitor& operator = (const WriterNodeVisitor&) { return *this; } /** * Fill the faces field of the mesh and call buildMesh(). * \param geo is the geode who contain vertice and faces. * \param listTriangles contain all the meshs faces. * \param texcoords tell us if we have to treat texture coord. */ void buildFaces(osg::Geode & geo, ListTriangle & listTriangles, bool texcoords); /** * Calculate the number of vertices in the geode. * \return the number of vertices in the geode. */ unsigned int calcVertices(osg::Geode & geo); /** * Build a mesh * \param geo is the geode who contain vertice and faces * \param index_vert is the index used to build the new mesh * \param texcoords tell us if we have to treat texture coord * \param mesh is the mesh with faces filled * \return the place of the box in the vector. * \sa See cutScene() about the definition of the boxes for faces sorting. */ void buildMesh(osg::Geode & geo, MapIndices & index_vert, bool texcoords, Lib3dsMesh *mesh); /** * Add a vertice to the index and link him with the Triangle index and the drawable. * \param index_vert is the map where the vertice are stored. * \param index is the indice of the vertice's position in the vec3. * \param drawable_n is the number of the drawable. * \return the position of the vertice in the final mesh. */ unsigned int getMeshIndexForGeometryIndex(MapIndices & index_vert, unsigned int index, unsigned int drawable_n); /** * Create the list of faces from the geode. * \param geo is the geode to study. * \param listTriangles is the list to fill. * \param texcoords tell us if we have to treat texture coord. * \param drawable_n tell us which drawable we are building. */ void createListTriangle(osg::Geometry * geo, ListTriangle & listTriangles, bool & texcoords, unsigned int & drawable_n); int processStateSet(osg::StateSet* stateset); std::string getUniqueName(const std::string& defaultvalue="", const std::string & defaultPrefix = "", bool nameIsPath = false); std::string export3DSTexture(const osg::Image * image, const std::string & fileName); typedef std::stack > StateSetStack; typedef std::map< osg::ref_ptr, Material, CompareStateSet> MaterialMap; bool _suceedLastApply; std::string _directory; std::string _srcDirectory; Lib3dsFile * file3ds; StateSetStack _stateSetStack; osg::ref_ptr _currentStateSet; std::map _mapPrefix; std::set _nameMap; MaterialMap _materialMap; unsigned int _lastGeneratedNumberedName; unsigned int _lastMaterialIndex; unsigned int _lastMeshIndex; Lib3dsMeshInstanceNode * _cur3dsNode; const osgDB::ReaderWriter::Options* options; unsigned int _imageCount; }; #endif