Files
OpenSceneGraph/src/osgPlugins/obj/OBJWriterNodeVisitor.h
2019-07-15 14:39:02 +02:00

161 lines
4.7 KiB
C++

// -*-c++-*-
/*
* Wavefront OBJ loader for Open Scene Graph
*
* Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
*
* Modified by Robert Osfield to support per Drawable coord, normal and
* texture coord arrays, bug fixes, and support for texture mapping.
*
* Writing support added 2007 by Stephan Huber, http://digitalmind.de,
* some ideas taken from the dae-plugin
*
* 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 OBJ_WRITER_NODE_VISITOR_HEADER__
#define OBJ_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 <set>
class OBJWriterNodeVisitor: public osg::NodeVisitor {
public:
OBJWriterNodeVisitor(std::ostream& fout, const std::string materialFileName = "") :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_fout(fout),
_currentStateSet(new osg::StateSet()),
_lastVertexIndex(1),
_lastNormalIndex(1),
_lastTexIndex(1)
{
_fout << "# file written by OpenSceneGraph" << std::endl << std::endl;
if (!materialFileName.empty()) {
_fout << "mtllib " << materialFileName << std::endl << std::endl;
}
}
virtual void apply(osg::Geometry & geometry);
virtual void apply(osg::Geode & node);
virtual void apply(osg::Group & node)
{
pushStateSet(node.getStateSet());
_nameStack.push_back( node.getName().empty() ? node.className() : node.getName() );
_fout << std::endl;
_fout << "g " << getUniqueName() << std::endl;
traverse( node );
_nameStack.pop_back();
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(std::ostream& fout);
class OBJMaterial {
public:
OBJMaterial() {}
OBJMaterial(osg::Material* mat, osg::Texture* tex);
osg::Vec4 diffuse, ambient, specular;
float shininess;
std::string image;
std::string name;
};
protected:
struct CompareStateSet
{
bool operator()(const osg::ref_ptr<osg::StateSet>& ss1, const osg::ref_ptr<osg::StateSet>& ss2) const
{
//std::cout << "CompareStateSet: " << ss1->compare(*ss2, false) << " " << ss1 << " " << ss2 << std::endl;
return ss1->compare(*ss2, true) < 0;
}
};
private:
OBJWriterNodeVisitor& operator = (const OBJWriterNodeVisitor&) { return *this; }
void processGeometry(osg::Geometry* geo, osg::Matrix& m);
void processArray(const std::string& key, osg::Array* array, const osg::Matrix& m = osg::Matrix::identity(), bool isNormal = false);
void processStateSet(osg::StateSet* stateset);
std::string getUniqueName(const std::string& defaultValue = "");
typedef std::stack<osg::ref_ptr<osg::StateSet> > StateSetStack;
typedef std::map< osg::ref_ptr<osg::StateSet>, OBJMaterial, CompareStateSet> MaterialMap;
std::ostream& _fout;
std::list<std::string> _nameStack;
StateSetStack _stateSetStack;
osg::ref_ptr<osg::StateSet> _currentStateSet;
std::map<std::string, unsigned int> _nameMap;
unsigned int _lastVertexIndex, _lastNormalIndex, _lastTexIndex;
MaterialMap _materialMap;
};
#endif