223 lines
7.9 KiB
C++
223 lines
7.9 KiB
C++
// -*-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 <string>
|
|
#include <stack>
|
|
#include <sstream>
|
|
|
|
#include <osg/Notify>
|
|
#include <osg/Node>
|
|
#include <osg/MatrixTransform>
|
|
#include <osg/Geode>
|
|
|
|
#include <osg/Geometry>
|
|
#include <osg/StateSet>
|
|
#include <osg/Material>
|
|
#include <osg/Texture2D>
|
|
#include <osg/TexGen>
|
|
#include <osg/TexMat>
|
|
|
|
#include <osgDB/Registry>
|
|
#include <osgDB/ReadFile>
|
|
#include <osgDB/FileUtils>
|
|
#include <osgDB/FileNameUtils>
|
|
|
|
#include <map>
|
|
|
|
#include "lib3ds/lib3ds.h"
|
|
#include "WriterCompareTriangle.h"
|
|
#include <set>
|
|
|
|
void copyOsgMatrixToLib3dsMatrix(Lib3dsMatrix lib3ds_matrix, const osg::Matrix& osg_matrix);
|
|
|
|
typedef std::map<std::pair<unsigned int, unsigned int>, unsigned int> MapIndices;
|
|
typedef std::vector<std::pair<Triangle, int> > ListTriangle; //the int is the drawable of the triangle
|
|
|
|
namespace plugin3ds
|
|
{
|
|
|
|
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);
|
|
|
|
bool succeeded() const { return _succeeded; }
|
|
virtual void apply(osg::Geode &node);
|
|
virtual void apply(osg::Billboard &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<osg::StateSet*>(_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<osg::Image> image;
|
|
bool texture_transparency;
|
|
bool texture_no_tile;
|
|
protected:
|
|
Material() : index(-1) {}
|
|
|
|
};
|
|
|
|
protected:
|
|
struct CompareStateSet
|
|
{
|
|
bool operator()(const osg::ref_ptr<osg::StateSet>& ss1, const osg::ref_ptr<osg::StateSet>& 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 mat Local to world matrix applied to the geode
|
|
* \param listTriangles contain all the meshs faces.
|
|
* \param texcoords tell us if we have to treat texture coord.
|
|
*/
|
|
void buildFaces(osg::Geode & geo, const osg::Matrix & mat, 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 mat Local to world matrix applied to the geode
|
|
* \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
|
|
* \sa See cutScene() about the definition of the boxes for faces sorting.
|
|
*/
|
|
void
|
|
buildMesh(osg::Geode & geo,
|
|
const osg::Matrix & mat,
|
|
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<osg::ref_ptr<osg::StateSet> > StateSetStack;
|
|
typedef std::map< osg::ref_ptr<osg::StateSet>, Material, CompareStateSet> MaterialMap;
|
|
|
|
void apply3DSMatrixNode(osg::Node &node, const osg::Matrix & m, const char * const prefix);
|
|
|
|
bool _succeeded;
|
|
std::string _directory;
|
|
std::string _srcDirectory;
|
|
Lib3dsFile * file3ds;
|
|
StateSetStack _stateSetStack;
|
|
osg::ref_ptr<osg::StateSet> _currentStateSet;
|
|
std::map<std::string, unsigned int> _mapPrefix; ///< List of next number to use in unique name generation, for each prefix
|
|
std::set<std::string> _nameMap;
|
|
MaterialMap _materialMap;
|
|
unsigned int _lastMaterialIndex;
|
|
unsigned int _lastMeshIndex;
|
|
Lib3dsMeshInstanceNode * _cur3dsNode;
|
|
const osgDB::ReaderWriter::Options* options;
|
|
unsigned int _imageCount;
|
|
bool _extendedFilePaths;
|
|
std::set<osg::Image *> _imageSet;
|
|
};
|
|
|
|
// end namespace plugin3ds
|
|
}
|
|
|
|
#endif
|