From Jan Peciva, "I am sending pov plugin for exporting scene to POV-Ray format.
POV-Ray is photorealistic ray tracer."
This commit is contained in:
@@ -175,6 +175,7 @@ ADD_SUBDIRECTORY(pic)
|
||||
ADD_SUBDIRECTORY(stl)
|
||||
ADD_SUBDIRECTORY(3ds)
|
||||
ADD_SUBDIRECTORY(ac)
|
||||
ADD_SUBDIRECTORY(pov)
|
||||
|
||||
ADD_SUBDIRECTORY(logo)
|
||||
ADD_SUBDIRECTORY(lws)
|
||||
|
||||
12
src/osgPlugins/pov/CMakeLists.txt
Normal file
12
src/osgPlugins/pov/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
INCLUDE(OsgMacroUtils)
|
||||
|
||||
SET(TARGET_SRC
|
||||
POVWriterNodeVisitor.cpp
|
||||
ReaderWriterPOV.cpp
|
||||
)
|
||||
SET(TARGET_HDRS
|
||||
POVWriterNodeVisitor.h
|
||||
ReaderWriterPOV.h
|
||||
)
|
||||
|
||||
SETUP_PLUGIN(pov)
|
||||
945
src/osgPlugins/pov/POVWriterNodeVisitor.cpp
Normal file
945
src/osgPlugins/pov/POVWriterNodeVisitor.cpp
Normal file
@@ -0,0 +1,945 @@
|
||||
//
|
||||
// POVWriterNodeVisitor converts OSG scene graph to POV (povray)
|
||||
// and writes it to the stream.
|
||||
//
|
||||
//
|
||||
// Autor: PCJohn (peciva _at fit.vutbr.cz)
|
||||
// developed for research purposes of Cadwork (c) and
|
||||
// Brno University of Technology (Czech Rep., EU)
|
||||
//
|
||||
// License: public domain
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
//
|
||||
// This source code is offered for use in the public domain.
|
||||
// You may use, modify or distribute it freely.
|
||||
//
|
||||
// This source code is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED
|
||||
// ARE HEREBY DISCLAIMED. This includes but is not limited to
|
||||
// warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// If you find the source code useful, authors will kindly welcome
|
||||
// if you give them credit and keep their names with their source
|
||||
// code, but you are not forced to do so.
|
||||
//
|
||||
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Material>
|
||||
#include <osg/TexEnv>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include "POVWriterNodeVisitor.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace osg;
|
||||
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::apply( Node& node )
|
||||
{
|
||||
POVWriterNodeVisitor::traverse( node );
|
||||
}
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::traverse( Node& node )
|
||||
{
|
||||
pushStateSet( node.getStateSet() );
|
||||
|
||||
NodeVisitor::traverse( node );
|
||||
|
||||
popStateSet( node.getStateSet() );
|
||||
}
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::pushStateSet( const StateSet *ss )
|
||||
{
|
||||
if( ss ) {
|
||||
|
||||
// merge state set
|
||||
StateSet *mergedSS = new StateSet(
|
||||
*_stateSetStack.top().get(), CopyOp::SHALLOW_COPY );
|
||||
mergedSS->merge( *ss );
|
||||
|
||||
// push state set
|
||||
_stateSetStack.push( mergedSS );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::popStateSet( const StateSet *ss )
|
||||
{
|
||||
if( ss ) {
|
||||
|
||||
// restore the previous stateset
|
||||
assert( _stateSetStack.size() > 0 && "_stateSetStack underflow" );
|
||||
_stateSetStack.pop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::apply( Geode& node )
|
||||
{
|
||||
pushStateSet( node.getStateSet() );
|
||||
|
||||
// iterate through drawables
|
||||
const Geode::DrawableList& dl = node.getDrawableList();
|
||||
for( Geode::DrawableList::const_iterator itr = dl.begin();
|
||||
itr != dl.end(); ++itr)
|
||||
{
|
||||
// get drawable
|
||||
const Drawable *d = *itr;
|
||||
|
||||
// push state set
|
||||
const StateSet *ss = d->getStateSet();
|
||||
if( ss ) pushStateSet( ss );
|
||||
|
||||
// transformation matrix
|
||||
Matrix m = _transformationStack.top();
|
||||
|
||||
// process lights
|
||||
processLights( _stateSetStack.top(), m );
|
||||
|
||||
// process geometry
|
||||
const Geometry *g = d->asGeometry();
|
||||
if( g )
|
||||
processGeometry( g, _stateSetStack.top(), m );
|
||||
|
||||
// pop state set
|
||||
if( ss ) popStateSet( ss );
|
||||
}
|
||||
|
||||
popStateSet( node.getStateSet() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ValueVisitor writes all values of an array out to a stream,
|
||||
* applies a matrix beforehand if necessary.
|
||||
*/
|
||||
// The code was adapted from the OBJWriterNodeVisitor.cpp.
|
||||
// See the file for the list of authors and contributors.
|
||||
class PovVec3WriterVisitor : public ConstValueVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
PovVec3WriterVisitor( ostream& fout, const Matrix& m =
|
||||
Matrix::identity(), bool isNormal = false)
|
||||
: ConstValueVisitor(),
|
||||
_fout( fout ),
|
||||
_m( m ),
|
||||
_isNormal( isNormal )
|
||||
{
|
||||
_applyMatrix = ( _m != Matrix::identity() );
|
||||
if ( _isNormal )
|
||||
_origin = Vec3( 0, 0, 0 ) * _m;
|
||||
}
|
||||
|
||||
virtual void apply( const Vec2& v )
|
||||
{
|
||||
apply( Vec3( v[0], v[1], 0. ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec3& v )
|
||||
{
|
||||
Vec3 a;
|
||||
if (_applyMatrix)
|
||||
a = (_isNormal) ? (v * _m) - _origin : v * _m;
|
||||
else
|
||||
a = v;
|
||||
_fout << " < " << a[0] << ", " << a[1] << ", " << a[2]
|
||||
<< " >" << endl;
|
||||
}
|
||||
|
||||
virtual void apply( const Vec2b& v )
|
||||
{
|
||||
apply( Vec3b( v[0], v[1], 0 ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec3b & v )
|
||||
{
|
||||
apply( Vec3s( v[0], v[1], v[2] ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec2s& v )
|
||||
{
|
||||
apply( Vec3s( v[0], v[1], 0 ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec3s& v )
|
||||
{
|
||||
apply( Vec3( v[0], v[1], v[2] ) );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PovVec3WriterVisitor& operator = ( const PovVec3WriterVisitor& ) { return *this; }
|
||||
|
||||
ostream& _fout;
|
||||
Matrix _m;
|
||||
bool _applyMatrix;
|
||||
bool _isNormal;
|
||||
Vec3 _origin;
|
||||
};
|
||||
|
||||
|
||||
class PovVec2WriterVisitor : public ConstValueVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
PovVec2WriterVisitor( ostream& fout, const Matrix& m =
|
||||
Matrix::identity(), bool isNormal = false)
|
||||
: ConstValueVisitor(),
|
||||
_fout( fout ),
|
||||
_m( m ),
|
||||
_isNormal( isNormal )
|
||||
{
|
||||
_applyMatrix = ( _m != Matrix::identity() );
|
||||
if ( _isNormal )
|
||||
_origin = Vec3( 0, 0, 0 ) * _m;
|
||||
}
|
||||
|
||||
virtual void apply( const Vec2& v )
|
||||
{
|
||||
Vec2 a;
|
||||
if (_applyMatrix) {
|
||||
Vec3 b( v[0], v[1], 0. );
|
||||
b = (_isNormal) ? (b * _m) - _origin : b * _m;
|
||||
a = Vec2( b[0], b[1] );
|
||||
} else
|
||||
a = v;
|
||||
_fout << " < " << a[0] << ", " << a[1] << " >" << endl;
|
||||
}
|
||||
|
||||
virtual void apply( const Vec3& v )
|
||||
{
|
||||
apply( Vec2( v[0], v[1] ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec2b& v )
|
||||
{
|
||||
apply( Vec2( v[0], v[1] ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec3b & v )
|
||||
{
|
||||
apply( Vec2b( v[0], v[1] ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec2s& v )
|
||||
{
|
||||
apply( Vec2( v[0], v[1] ) );
|
||||
}
|
||||
|
||||
virtual void apply( const Vec3s& v )
|
||||
{
|
||||
apply( Vec2s( v[0], v[1] ) );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PovVec2WriterVisitor& operator = ( const PovVec2WriterVisitor& ) { return *this; }
|
||||
|
||||
ostream& _fout;
|
||||
Matrix _m;
|
||||
bool _applyMatrix;
|
||||
bool _isNormal;
|
||||
Vec3 _origin;
|
||||
};
|
||||
|
||||
|
||||
class ArrayValueFunctor : public ConstArrayVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
ArrayValueFunctor( ConstValueVisitor &vv )
|
||||
: valueVisitor( &vv ) {}
|
||||
|
||||
template< class ArrayType, class ValueType >
|
||||
void visitAll( const ArrayType& a ) {
|
||||
const ValueType *v = static_cast< const ValueType* >( a.getDataPointer() );
|
||||
unsigned int size = a.getNumElements();
|
||||
for( unsigned int i=0; i<size; i++ )
|
||||
valueVisitor->apply( v[i] );
|
||||
}
|
||||
virtual void apply( const ByteArray& a ) { visitAll< ByteArray, GLbyte >( a ); }
|
||||
virtual void apply( const ShortArray& a ) { visitAll< ShortArray, GLshort >( a ); }
|
||||
virtual void apply( const IntArray& a ) { visitAll< IntArray, GLint >( a ); }
|
||||
virtual void apply( const UByteArray& a ) { visitAll< UByteArray, GLubyte >( a ); }
|
||||
virtual void apply( const UShortArray& a ) { visitAll< UShortArray, GLushort >( a ); }
|
||||
virtual void apply( const UIntArray& a ) { visitAll< UIntArray, GLuint >( a ); }
|
||||
virtual void apply( const FloatArray& a ) { visitAll< FloatArray, GLfloat >( a ); }
|
||||
virtual void apply( const DoubleArray& a ) { visitAll< DoubleArray, GLdouble >( a ); }
|
||||
virtual void apply( const Vec2Array& a ) { visitAll< Vec2Array, Vec2 >( a ); }
|
||||
virtual void apply( const Vec3Array& a ) { visitAll< Vec3Array, Vec3 >( a ); }
|
||||
virtual void apply( const Vec4Array& a ) { visitAll< Vec4Array, Vec4 >( a ); }
|
||||
virtual void apply( const Vec4ubArray& a ) { visitAll< Vec4ubArray, Vec4ub >( a ); }
|
||||
virtual void apply( const Vec2bArray& a ) { visitAll< Vec2bArray, Vec2b >( a ); }
|
||||
virtual void apply( const Vec3bArray& a ) { visitAll< Vec3bArray, Vec3b >( a ); }
|
||||
virtual void apply( const Vec4bArray& a ) { visitAll< Vec4bArray, Vec4b >( a ); }
|
||||
virtual void apply( const Vec2sArray& a ) { visitAll< Vec2sArray, Vec2s >( a ); }
|
||||
virtual void apply( const Vec3sArray& a ) { visitAll< Vec3sArray, Vec3s >( a ); }
|
||||
virtual void apply( const Vec4sArray& a ) { visitAll< Vec4sArray, Vec4s >( a ); }
|
||||
virtual void apply( const Vec2dArray& a ) { visitAll< Vec2dArray, Vec2d >( a ); }
|
||||
virtual void apply( const Vec3dArray& a ) { visitAll< Vec3dArray, Vec3d >( a ); }
|
||||
virtual void apply( const Vec4dArray& a ) { visitAll< Vec4dArray, Vec4d >( a ); }
|
||||
|
||||
virtual void apply( const Array& ) {
|
||||
assert( false && "Not using overloaded methods." );
|
||||
}
|
||||
|
||||
protected:
|
||||
ConstValueVisitor *valueVisitor;
|
||||
};
|
||||
|
||||
|
||||
template < class Type >
|
||||
class PovArrayWriterFunctor : public ArrayValueFunctor
|
||||
{
|
||||
public:
|
||||
PovArrayWriterFunctor( ostream& fout, const Matrix& m =
|
||||
Matrix::identity(), bool isNormal = false)
|
||||
: ArrayValueFunctor( povValueVisitor ),
|
||||
povValueVisitor( fout, m, isNormal ) {}
|
||||
|
||||
protected:
|
||||
Type povValueVisitor;
|
||||
};
|
||||
|
||||
|
||||
static void writeIndex( ostream& _fout, unsigned int &numTriangles,
|
||||
int i1, int i2, int i3, int &numOnLine )
|
||||
{
|
||||
// produce comma, except the first record
|
||||
if( numTriangles != 0 )
|
||||
_fout << ",";
|
||||
|
||||
// new line each four triangles
|
||||
if( numOnLine == 3 ) {
|
||||
_fout << endl;
|
||||
_fout << " ";
|
||||
numOnLine = 0;
|
||||
}
|
||||
|
||||
_fout << " < " << i1 << ", " << i2 << ", " << i3 << " >";
|
||||
numOnLine++;
|
||||
}
|
||||
|
||||
|
||||
static void processDrawArrays( ostream& _fout, unsigned int &numTriangles,
|
||||
GLenum mode, int startIndex, int stopIndex )
|
||||
{
|
||||
int numOnLine = 0;
|
||||
|
||||
int i = startIndex;
|
||||
switch( mode ) {
|
||||
|
||||
case GL_TRIANGLES:
|
||||
for( i += 2; i < stopIndex; i += 3, numTriangles++ )
|
||||
writeIndex( _fout, numTriangles, i-2, i-1, i, numOnLine );
|
||||
break;
|
||||
|
||||
case GL_TRIANGLE_STRIP:
|
||||
for( i += 2; i < stopIndex; i += 1, numTriangles++ )
|
||||
writeIndex( _fout, numTriangles, i-2, i-1, i, numOnLine );
|
||||
break;
|
||||
|
||||
case GL_TRIANGLE_FAN:
|
||||
for( i += 2; i < stopIndex; i += 1, numTriangles++ )
|
||||
writeIndex( _fout, numTriangles, startIndex, i-1, i, numOnLine );
|
||||
break;
|
||||
|
||||
case GL_QUADS:
|
||||
case GL_QUAD_STRIP:
|
||||
case GL_POLYGON:
|
||||
assert( 0 && "Not implemented yet." );
|
||||
|
||||
default:
|
||||
assert( false );
|
||||
}
|
||||
|
||||
// put new line when primitive set is over
|
||||
_fout << endl;
|
||||
}
|
||||
|
||||
|
||||
class DrawElementsWriter : public ConstValueVisitor {
|
||||
public:
|
||||
|
||||
DrawElementsWriter( ostream& fout ) : _fout(fout),
|
||||
numIndices( 0 ), numOnLine( 0 ),
|
||||
numTriangles( 0 ) {}
|
||||
|
||||
virtual void apply( const GLubyte& b ) { processIndex( b ); }
|
||||
virtual void apply( const GLushort& s ) { processIndex( s ); }
|
||||
virtual void apply( const GLuint& i ) { processIndex( i ); }
|
||||
|
||||
virtual void processIndex( const GLuint i ) = 0;
|
||||
|
||||
inline unsigned int getNumTriangles() { return numTriangles; }
|
||||
|
||||
protected:
|
||||
ostream& _fout;
|
||||
GLuint indices[3];
|
||||
int numIndices;
|
||||
int numOnLine;
|
||||
unsigned int numTriangles;
|
||||
|
||||
virtual bool processTriangle()
|
||||
{
|
||||
// dont produce trinagle until we have got three vertices
|
||||
if( numIndices < 3 )
|
||||
return false;
|
||||
|
||||
// produce comma, except the first record
|
||||
if( numTriangles != 0 )
|
||||
_fout << ",";
|
||||
|
||||
// new line each four triangles
|
||||
if( numOnLine == 3 ) {
|
||||
_fout << endl;
|
||||
_fout << " ";
|
||||
numOnLine = 0;
|
||||
}
|
||||
|
||||
// print out indices
|
||||
_fout << " <" << indices[0] << "," << indices[1]
|
||||
<< "," << indices[2] << ">";
|
||||
|
||||
// increment counters
|
||||
numTriangles++;
|
||||
numOnLine++;
|
||||
|
||||
// triangle produced => return true
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TriangleWriter : public DrawElementsWriter {
|
||||
public:
|
||||
TriangleWriter( ostream& fout ) : DrawElementsWriter( fout ) {}
|
||||
|
||||
virtual void processIndex( const GLuint i )
|
||||
{
|
||||
indices[numIndices++] = i;
|
||||
|
||||
if( processTriangle() )
|
||||
numIndices = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TriangleStripWriter : public DrawElementsWriter {
|
||||
public:
|
||||
TriangleStripWriter( ostream& fout ) : DrawElementsWriter( fout ) {}
|
||||
|
||||
virtual void processIndex( const GLuint i )
|
||||
{
|
||||
indices[0] = indices[1];
|
||||
indices[1] = indices[2];
|
||||
indices[2] = i;
|
||||
numIndices++;
|
||||
|
||||
processTriangle();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TriangleFanWriter : public DrawElementsWriter {
|
||||
public:
|
||||
TriangleFanWriter( ostream& fout ) : DrawElementsWriter( fout ) {}
|
||||
|
||||
virtual void processIndex( const GLuint i )
|
||||
{
|
||||
if( numIndices == 0 ) {
|
||||
indices[0] = i;
|
||||
numIndices++;
|
||||
return;
|
||||
}
|
||||
|
||||
indices[1] = indices[2];
|
||||
indices[2] = i;
|
||||
numIndices++;
|
||||
|
||||
processTriangle();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template < class Type, class IterType >
|
||||
static void processDrawElements( const PrimitiveSet *pset, DrawElementsWriter *w )
|
||||
{
|
||||
const Type *drawElements =
|
||||
dynamic_cast< const Type* >( pset );
|
||||
for( IterType primItr = drawElements->begin();
|
||||
primItr != drawElements->end();
|
||||
++primItr )
|
||||
w->apply( *primItr );
|
||||
}
|
||||
|
||||
|
||||
class Vec4ConvertVisitor : public ConstValueVisitor
|
||||
{
|
||||
public:
|
||||
//virtual void apply( const GLbyte& v )
|
||||
//virtual void apply( const GLshort& v )
|
||||
//virtual void apply( const GLint& v )
|
||||
//virtual void apply( const GLushort& v )
|
||||
//virtual void apply( const GLubyte& v )
|
||||
//virtual void apply( const GLuint& v )
|
||||
//virtual void apply( const GLfloat& v )
|
||||
//virtual void apply( const GLdouble& v )
|
||||
virtual void apply( const Vec4ub& v ) { r = Vec4( v[0], v[1], v[2], v[3] ); }
|
||||
//virtual void apply( const Vec2& v )
|
||||
virtual void apply( const Vec3& v ) { r = Vec4( v[0], v[1], v[2], 1. ); }
|
||||
virtual void apply( const Vec4& v ) { r = v; }
|
||||
//virtual void apply( const Vec2b& v )
|
||||
virtual void apply( const Vec3b& v ) { r = Vec4( v[0], v[1], v[2], 1. ); }
|
||||
virtual void apply( const Vec4b& v ) { r = Vec4( v[0], v[1], v[2], v[3] ); }
|
||||
//virtual void apply( const Vec2s& v )
|
||||
virtual void apply( const Vec3s& v ) { r = Vec4( v[0], v[1], v[2], 1. ); }
|
||||
virtual void apply( const Vec4s& v ) { r = Vec4( v[0], v[1], v[2], v[3] ); }
|
||||
//virtual void apply( const Vec2d& v )
|
||||
virtual void apply( const Vec3d& v ) { r = Vec4( v[0], v[1], v[2], 1. ); }
|
||||
virtual void apply( const Vec4d& v ) { r = Vec4( v[0], v[1], v[2], v[3] ); }
|
||||
|
||||
const Vec4& getResult() const { return r; }
|
||||
|
||||
protected:
|
||||
Vec4 r;
|
||||
};
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::processGeometry( const Geometry *g,
|
||||
const StateSet *ss,
|
||||
const Matrix &m )
|
||||
{
|
||||
// ignore empty geometries because they cause povray to fail loading the model
|
||||
// (seen on POV-Ray 3.6.1)
|
||||
if( g->getVertexArray() == NULL || g->getVertexArray()->getNumElements() == 0 )
|
||||
return;
|
||||
|
||||
if(( g->getVertexIndices() != NULL &&
|
||||
g->getVertexIndices()->getNumElements() != 0 ) ||
|
||||
( g->getNormalIndices() != NULL &&
|
||||
g->getNormalIndices()->getNumElements() != 0 ) ||
|
||||
( g->getTexCoordIndices(0) != NULL &&
|
||||
g->getTexCoordIndices(0)->getNumElements() != 0 ))
|
||||
{
|
||||
notify( WARN ) << "POV Writer WARNING: "
|
||||
"Geometry with indices is not " << endl <<
|
||||
"supported yet by POV plugin. Skipping geometry." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// mesh2
|
||||
_fout << "mesh2" << endl;
|
||||
_fout << "{" << endl;
|
||||
|
||||
// Convert coordinates
|
||||
// OSG represents coordinates by: Vec2, Vec3, Vec4
|
||||
if( g->getVertexArray() ) {
|
||||
|
||||
_fout << " vertex_vectors" << endl;
|
||||
_fout << " {" << endl;
|
||||
_fout << " " << g->getVertexArray()->getNumElements() << "," << endl;
|
||||
|
||||
PovArrayWriterFunctor< PovVec3WriterVisitor > povArrayWriter( _fout, m, false );
|
||||
g->getVertexArray()->accept( povArrayWriter );
|
||||
|
||||
_fout << " }" << endl;
|
||||
}
|
||||
|
||||
// reuse coord indices for normal and texCoord
|
||||
bool needNormalIndices = true;
|
||||
bool needTexCoordIndices = true;
|
||||
|
||||
// Convert normals
|
||||
// OSG represents normals by: Vec3,Vec3s,Vec3b
|
||||
// and can handle: Vec4s,Vec4b by truncating them to three components
|
||||
if( g->getNormalArray() ) {
|
||||
|
||||
_fout << " normal_vectors" << endl;
|
||||
_fout << " {" << endl;
|
||||
_fout << " " << g->getNormalArray()->getNumElements() << "," << endl;
|
||||
|
||||
PovArrayWriterFunctor< PovVec3WriterVisitor > povArrayWriter( _fout, m, true );
|
||||
g->getNormalArray()->accept( povArrayWriter );
|
||||
|
||||
_fout << " }" << endl;
|
||||
|
||||
// need normal indices?
|
||||
if( g->getVertexArray() )
|
||||
if( g->getVertexArray()->getNumElements() == g->getNormalArray()->getNumElements() )
|
||||
needNormalIndices = false;
|
||||
}
|
||||
|
||||
// Convert texture coordinates
|
||||
if( g->getTexCoordArray( 0 ) ) {
|
||||
|
||||
_fout << " uv_vectors" << endl;
|
||||
_fout << " {" << endl;
|
||||
_fout << " " << g->getTexCoordArray( 0 )->getNumElements() << "," << endl;
|
||||
|
||||
// texture coordinates
|
||||
PovArrayWriterFunctor< PovVec2WriterVisitor > povArrayWriter( _fout );
|
||||
g->getTexCoordArray( 0 )->accept( povArrayWriter );
|
||||
|
||||
_fout << " }" << endl;
|
||||
|
||||
// need texCoord indices?
|
||||
if( g->getVertexArray() )
|
||||
if( g->getVertexArray()->getNumElements() == g->getTexCoordArray( 0 )->getNumElements() )
|
||||
needTexCoordIndices = false;
|
||||
}
|
||||
|
||||
// indices string stream
|
||||
stringstream indicesStream;
|
||||
indicesStream << " ";
|
||||
unsigned int numTriangles = 0;
|
||||
|
||||
// process primitive sets
|
||||
int psetIndex, numPsets = g->getNumPrimitiveSets();
|
||||
for( psetIndex = 0; psetIndex < numPsets; psetIndex++ ) {
|
||||
|
||||
// get primitive set
|
||||
const PrimitiveSet *pset = g->getPrimitiveSet( psetIndex );
|
||||
PrimitiveSet::Type type = pset->getType();
|
||||
GLenum mode = pset->getMode();
|
||||
|
||||
// skip not supported primitives
|
||||
switch( mode ) {
|
||||
case GL_TRIANGLES:
|
||||
case GL_TRIANGLE_STRIP:
|
||||
case GL_TRIANGLE_FAN:
|
||||
case GL_QUADS:
|
||||
case GL_QUAD_STRIP:
|
||||
case GL_POLYGON:
|
||||
break; // only supported types
|
||||
default:
|
||||
continue; // skip primitive set
|
||||
// Povray does not support lines and points
|
||||
};
|
||||
|
||||
switch( type ) {
|
||||
case PrimitiveSet::DrawArraysPrimitiveType:
|
||||
{
|
||||
const DrawArrays *drawArrays = dynamic_cast< const DrawArrays* >( pset );
|
||||
|
||||
int startIndex = drawArrays->getFirst();
|
||||
int stopIndex = startIndex + drawArrays->getCount();
|
||||
|
||||
// FIXME: Am I using startIndex for all bundles that are PER_VERTEX?
|
||||
|
||||
processDrawArrays( indicesStream, numTriangles,
|
||||
mode, startIndex, stopIndex );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveSet::DrawArrayLengthsPrimitiveType:
|
||||
{
|
||||
const DrawArrayLengths *drawArrayLengths =
|
||||
dynamic_cast< const DrawArrayLengths* >( pset );
|
||||
|
||||
int startIndex = drawArrayLengths->getFirst();
|
||||
DrawArrayLengths::vector_type::const_iterator itr = drawArrayLengths->begin();
|
||||
|
||||
for( ; itr != drawArrayLengths->end(); itr++ ) {
|
||||
processDrawArrays( indicesStream, numTriangles,
|
||||
mode, startIndex, *itr );
|
||||
startIndex += *itr;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveSet::DrawElementsUBytePrimitiveType:
|
||||
case PrimitiveSet::DrawElementsUShortPrimitiveType:
|
||||
case PrimitiveSet::DrawElementsUIntPrimitiveType:
|
||||
{
|
||||
DrawElementsWriter *w;
|
||||
switch( mode ) {
|
||||
case GL_TRIANGLES:
|
||||
w = new TriangleWriter( indicesStream );
|
||||
break;
|
||||
case GL_TRIANGLE_STRIP:
|
||||
w = new TriangleStripWriter( indicesStream );
|
||||
break;
|
||||
case GL_TRIANGLE_FAN:
|
||||
w = new TriangleFanWriter( indicesStream );
|
||||
break;
|
||||
default:
|
||||
assert( false && "Not implemented yet." );
|
||||
goto skip;
|
||||
}
|
||||
|
||||
switch( type ) {
|
||||
|
||||
case PrimitiveSet::DrawElementsUBytePrimitiveType:
|
||||
processDrawElements< DrawElementsUByte,
|
||||
DrawElementsUByte::const_iterator >( pset, w );
|
||||
break;
|
||||
|
||||
case PrimitiveSet::DrawElementsUShortPrimitiveType:
|
||||
processDrawElements< DrawElementsUShort,
|
||||
DrawElementsUShort::const_iterator >( pset, w );
|
||||
break;
|
||||
|
||||
case PrimitiveSet::DrawElementsUIntPrimitiveType:
|
||||
processDrawElements< DrawElementsUInt,
|
||||
DrawElementsUInt::const_iterator >( pset, w );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( false );
|
||||
}
|
||||
|
||||
numTriangles += w->getNumTriangles();
|
||||
|
||||
delete w;
|
||||
}
|
||||
skip:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( false && "Primitive set not handled." );
|
||||
}
|
||||
}
|
||||
|
||||
const Texture *texture = dynamic_cast< const Texture* >(
|
||||
ss->getTextureAttribute( 0, StateAttribute::TEXTURE ));
|
||||
const Image *image = ( texture ? texture->getImage( 0 ) : NULL );
|
||||
// TexEnv not used yet
|
||||
//const TexEnv *texEnv = dynamic_cast< const TexEnv* >(
|
||||
// ss->getTextureAttribute( 0, StateAttribute::TEXENV ));
|
||||
bool texturing2D = ss->getTextureMode( 0, GL_TEXTURE_2D ) != 0;
|
||||
|
||||
_fout << " face_indices" << endl
|
||||
<< " {" << endl
|
||||
<< " " << numTriangles << "," << endl
|
||||
<< indicesStream.str()
|
||||
<< " }" << endl;
|
||||
|
||||
if( needNormalIndices )
|
||||
_fout << " normal_indices" << endl
|
||||
<< " {" << endl
|
||||
<< " " << numTriangles << "," << endl
|
||||
<< indicesStream.str()
|
||||
<< " }" << endl;
|
||||
|
||||
if( needTexCoordIndices )
|
||||
_fout << " uv_indices" << endl
|
||||
<< " {" << endl
|
||||
<< " " << numTriangles << "," << endl
|
||||
<< indicesStream.str()
|
||||
<< " }" << endl;
|
||||
|
||||
// POV-Ray's surface properties
|
||||
_fout << " texture {" << endl;
|
||||
|
||||
#if 1
|
||||
|
||||
// color variables
|
||||
Vec4f ambient( 0.2f, 0.2f, 0.2f, 1.f );
|
||||
Vec4f diffuse( 0.8f, 0.8f, 0.8f, 1.f );
|
||||
Vec4f specular( 0.f, 0.f, 0.f, 1.f );
|
||||
Vec4f pigmentColor;
|
||||
|
||||
// get ambient and diffuse
|
||||
const Material *material = dynamic_cast< const Material* >(
|
||||
ss->getAttribute( StateAttribute::MATERIAL ) );
|
||||
if( !material ) {
|
||||
const Array *a = g->getColorArray();
|
||||
if( a && a->getNumElements() > 0 ) {
|
||||
Vec4ConvertVisitor cv;
|
||||
g->getColorArray()->accept( 0, cv );
|
||||
diffuse = cv.getResult();
|
||||
}
|
||||
} else {
|
||||
diffuse = material->getDiffuse( Material::FRONT );
|
||||
ambient = material->getAmbient( Material::FRONT );
|
||||
specular = material->getSpecular( Material::FRONT );
|
||||
}
|
||||
|
||||
// compute intensities
|
||||
float diffuseIntensity = diffuse.r() + diffuse.g() + diffuse.b();
|
||||
float ambientIntensity = ambient.r() + ambient.g() + ambient.b();
|
||||
float specularIntensity = specular.r() + specular.g() + specular.b();
|
||||
|
||||
// pigment color defaults to diffuse
|
||||
pigmentColor = diffuse;
|
||||
float pigmentIntensity = diffuseIntensity;
|
||||
|
||||
// if diffuse is too dark and ambient is strong, use it instead
|
||||
if( diffuseIntensity < 2 * ambientIntensity ) {
|
||||
pigmentColor = ambient;
|
||||
pigmentIntensity = ambientIntensity;
|
||||
}
|
||||
|
||||
#else
|
||||
Vec4ConvertVisitor cv;
|
||||
g->getColorArray()->accept( 0, cv );
|
||||
Vec4 pigmentColor = cv.getResult();
|
||||
#endif
|
||||
|
||||
// has 2D texture => produce image_map
|
||||
if( texturing2D && texture && image ) {
|
||||
string fileName = image->getFileName();
|
||||
|
||||
// replace '\' by '/'
|
||||
// ('\' does not work on Linux POV-Ray)
|
||||
// FIXME: is '/' working on Windows?
|
||||
string::size_type i=0;
|
||||
while( ( i = fileName.find( '\\', i ) ) != string::npos )
|
||||
fileName[i] = '/';
|
||||
|
||||
_fout << " uv_mapping pigment {" << endl
|
||||
<< " image_map { png \"" << fileName << "\" }" << endl
|
||||
<< " }" << endl;
|
||||
|
||||
// no 2D texture => produce single color
|
||||
} else {
|
||||
|
||||
// rgb and f as filter (for transparency, 0 - opaque, 1 - transparent)
|
||||
_fout << " pigment {" << endl
|
||||
<< " color rgbf < " << pigmentColor[0] << ", "
|
||||
<< pigmentColor[1] << ", "
|
||||
<< pigmentColor[2] << ", 0 >" << endl
|
||||
<< " }" << endl;
|
||||
}
|
||||
|
||||
// POV-Ray's finish
|
||||
float ai = (pigmentIntensity != 0) ? ambientIntensity/pigmentIntensity : 0.f;
|
||||
float di = (pigmentIntensity != 0) ? diffuseIntensity/pigmentIntensity : 0.f;
|
||||
_fout << " finish { ambient " << ai << endl
|
||||
<< " diffuse " << di << endl
|
||||
<< " specular " << specularIntensity/3. << endl
|
||||
<< " reflection " << specularIntensity/3. << endl
|
||||
<< " }" << endl
|
||||
<< " }" << endl;
|
||||
|
||||
_fout << "}" << endl;
|
||||
|
||||
numProducedTriangles += numTriangles;
|
||||
}
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::processLights( const StateSet *ss, const Matrix &m )
|
||||
{
|
||||
const StateSet::AttributeList &attributeList = ss->getAttributeList();
|
||||
StateSet::AttributeList::const_iterator it = attributeList.begin();
|
||||
for( ; it!=attributeList.end(); ++it )
|
||||
if( it->first.first == StateAttribute::LIGHT ) {
|
||||
Light *l = dynamic_cast< Light* >( it->second.first.get() );
|
||||
if( l &&
|
||||
ss->getMode( GL_LIGHT0 + l->getLightNum() ) & StateAttribute::ON &&
|
||||
lights.find( l ) == lights.end() ) {
|
||||
|
||||
// append the light into the map
|
||||
lights[ l ] = 1; // use any number (the number is not used)
|
||||
|
||||
// directional light requires special treatment
|
||||
Vec4 pos4 = l->getPosition();
|
||||
Vec3 pos3( pos4.x(), pos4.y(), pos4.z() );
|
||||
bool directional = (pos4.w() == 0.);
|
||||
bool spot = false;
|
||||
if( directional ) {
|
||||
pos3.normalize();
|
||||
pos3 = bound.center() + ( pos3 * bound.radius() * 1.01f );
|
||||
} else {
|
||||
pos3 /= pos4.w();
|
||||
spot = !equivalent( l->getSpotCutoff(), 180.f );
|
||||
}
|
||||
|
||||
// create the light code
|
||||
_fout << "light_source {" << endl;
|
||||
|
||||
// position
|
||||
PovVec3WriterVisitor povVec3Writer( _fout, m );
|
||||
povVec3Writer.apply( pos3 );
|
||||
|
||||
// color
|
||||
// note: transmit and filter color values are ignored
|
||||
// by POV-Ray for light sources
|
||||
// (see POV-Ray's (version 3.6.1, chapter 2.4.7) doc:
|
||||
// http://www.povray.org/documentation/view/3.6.1/308/)
|
||||
_fout << " color rgb";
|
||||
PovVec3WriterVisitor povColorWriter( _fout );
|
||||
const Vec3::value_type *f = l->getDiffuse().ptr();
|
||||
povColorWriter.apply( Vec3( f[0], f[1], f[2] ) );
|
||||
|
||||
// directional light
|
||||
if( directional ) {
|
||||
_fout << " parallel" << endl
|
||||
<< " point_at";
|
||||
povVec3Writer.apply( bound.center() );
|
||||
}
|
||||
|
||||
// spot light
|
||||
if( spot ) {
|
||||
_fout << " spotlight" << endl
|
||||
<< " point_at";
|
||||
povVec3Writer.apply( pos3 + l->getDirection() );
|
||||
// FIXME: radius and tightness models the light distribution
|
||||
// differently than OpenGL's shininess. So, different
|
||||
// visual results are produced. The difference can be lowered
|
||||
// much by computing radius.
|
||||
_fout << " falloff " << l->getSpotCutoff() << endl
|
||||
<< " radius 0" << endl
|
||||
<< " tightness " << l->getSpotExponent() / 128.f * 100.f << endl;
|
||||
}
|
||||
|
||||
// light source end
|
||||
_fout << "}" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void POVWriterNodeVisitor::apply( Transform& node )
|
||||
{
|
||||
// push new transformation on transformation stack
|
||||
Matrix m = _transformationStack.top();
|
||||
node.computeLocalToWorldMatrix( m, this );
|
||||
_transformationStack.push( m );
|
||||
|
||||
// traverse the node
|
||||
apply( (Group&)node );
|
||||
|
||||
// pop transformation
|
||||
_transformationStack.pop();
|
||||
}
|
||||
|
||||
|
||||
POVWriterNodeVisitor::POVWriterNodeVisitor( ostream& fout, const BoundingSphere& b )
|
||||
: NodeVisitor(TRAVERSE_ALL_CHILDREN),
|
||||
_fout( fout ),
|
||||
bound( b ),
|
||||
numProducedTriangles( 0 )
|
||||
{
|
||||
_stateSetStack.push( new StateSet() );
|
||||
_transformationStack.push( Matrix( 1., 0.,0.,0.,
|
||||
0., 0.,1.,0.,
|
||||
0., 1.,0.,0.,
|
||||
0., 0.,0.,1. ) );
|
||||
}
|
||||
|
||||
|
||||
POVWriterNodeVisitor::~POVWriterNodeVisitor()
|
||||
{
|
||||
assert( _stateSetStack.size() >= 1 && "_stateSetStack underflow." );
|
||||
assert( _stateSetStack.size() <= 1 && "_stateSetStack overflow." );
|
||||
assert( _transformationStack.size() >= 1 && "_transformationStack underflow." );
|
||||
assert( _transformationStack.size() <= 1 && "_transformationStack overflow." );
|
||||
_stateSetStack.pop();
|
||||
_transformationStack.pop();
|
||||
}
|
||||
93
src/osgPlugins/pov/POVWriterNodeVisitor.h
Normal file
93
src/osgPlugins/pov/POVWriterNodeVisitor.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef POV_WRITER_NODE_VISITOR_H
|
||||
#define POV_WRITER_NODE_VISITOR_H
|
||||
//
|
||||
// POVWriterNodeVisitor converts OSG scene graph to POV (povray)
|
||||
// and writes it to the stream.
|
||||
//
|
||||
//
|
||||
// Autor: PCJohn (peciva _at fit.vutbr.cz)
|
||||
// developed for research purposes of Cadwork (c) and
|
||||
// Brno University of Technology (Czech Rep., EU)
|
||||
//
|
||||
// License: public domain
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
//
|
||||
// This source code is offered for use in the public domain.
|
||||
// You may use, modify or distribute it freely.
|
||||
//
|
||||
// This source code is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED
|
||||
// ARE HEREBY DISCLAIMED. This includes but is not limited to
|
||||
// warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// If you find the source code useful, authors will kindly welcome
|
||||
// if you give them credit and keep their names with their source
|
||||
// code, but you are not forced to do so.
|
||||
//
|
||||
|
||||
#include <osg/NodeVisitor>
|
||||
#include <stack>
|
||||
|
||||
namespace osg {
|
||||
class Light;
|
||||
class Transform;
|
||||
}
|
||||
|
||||
|
||||
class POVWriterNodeVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
POVWriterNodeVisitor( std::ostream& fout, const osg::BoundingSphere& bound );
|
||||
virtual ~POVWriterNodeVisitor();
|
||||
|
||||
void traverse( osg::Node& node );
|
||||
|
||||
virtual void apply( osg::Node &node );
|
||||
virtual void apply( osg::Geode &node );
|
||||
//virtual void apply(osg::Group &node);
|
||||
|
||||
//virtual void apply(osg::Billboard& node);
|
||||
//virtual void apply(ProxyNode& node) { apply((Group&)node); }
|
||||
//virtual void apply(Projection& node) { apply((Group&)node); }
|
||||
//virtual void apply(CoordinateSystemNode& node) { apply((Group&)node); }
|
||||
|
||||
//virtual void apply(ClipNode& node) { apply((Group&)node); }
|
||||
//virtual void apply(TexGenNode& node) { apply((Group&)node); }
|
||||
//virtual void apply(LightSource& node) { apply((Group&)node); }
|
||||
|
||||
virtual void apply( osg::Transform& node );
|
||||
//virtual void apply(Camera& node) { apply((Transform&)node); }
|
||||
//virtual void apply(CameraView& node) { apply((Transform&)node); }
|
||||
//virtual void apply(osg::MatrixTransform& node);
|
||||
//virtual void apply(osg::PositionAttitudeTransform& node);
|
||||
|
||||
//virtual void apply(Switch& node) { apply((Group&)node); }
|
||||
//virtual void apply(Sequence& node) { apply((Group&)node); }
|
||||
//virtual void apply(osg::LOD& node);
|
||||
//virtual void apply(PagedLOD& node) { apply((LOD&)node); }
|
||||
//virtual void apply(ClearNode& node) { apply((Group&)node); }
|
||||
//virtual void apply(OccluderNode& node) { apply((Group&)node); }
|
||||
|
||||
unsigned int getNumProducedTriangles() const { return numProducedTriangles; }
|
||||
protected:
|
||||
|
||||
std::ostream& _fout;
|
||||
osg::BoundingSphere bound;
|
||||
std::stack< osg::ref_ptr< osg::StateSet > > _stateSetStack;
|
||||
std::stack< osg::Matrix > _transformationStack;
|
||||
unsigned int numProducedTriangles;
|
||||
std::map< osg::Light*, int > lights;
|
||||
|
||||
void pushStateSet( const osg::StateSet *ss );
|
||||
void popStateSet( const osg::StateSet *ss );
|
||||
|
||||
virtual void processGeometry( const osg::Geometry *g,
|
||||
const osg::StateSet *ss, const osg::Matrix &m );
|
||||
virtual void processLights( const osg::StateSet *ss, const osg::Matrix &m );
|
||||
};
|
||||
|
||||
|
||||
#endif /* POV_WRITER_NODE_VISITOR_H */
|
||||
123
src/osgPlugins/pov/ReaderWriterPOV.cpp
Normal file
123
src/osgPlugins/pov/ReaderWriterPOV.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <osg/ComputeBoundsVisitor>
|
||||
#include <osg/io_utils>
|
||||
#include <osg/Notify>
|
||||
#include <osgDB/FileUtils>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include "ReaderWriterPOV.h"
|
||||
#include "POVWriterNodeVisitor.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace osg;
|
||||
|
||||
|
||||
// Register with Registry to instantiate the Povray writer.
|
||||
REGISTER_OSGPLUGIN( Povray, ReaderWriterPOV )
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Initializes the ReaderWriterPOV.
|
||||
*/
|
||||
ReaderWriterPOV::ReaderWriterPOV()
|
||||
{
|
||||
// Set supported extensions and options
|
||||
supportsExtension( "pov", "POV-Ray format" );
|
||||
}
|
||||
|
||||
|
||||
static osgDB::ReaderWriter::WriteResult
|
||||
writeNodeImplementation( const Node& node, ostream& fout,
|
||||
const osgDB::ReaderWriter::Options* options )
|
||||
{
|
||||
// get camera on the top of scene graph
|
||||
const Camera *camera = dynamic_cast< const Camera* >( &node );
|
||||
|
||||
Vec3d eye, center, up, right;
|
||||
double fovy, aspectRatio, tmp;
|
||||
if( camera ) {
|
||||
|
||||
// view matrix
|
||||
camera->getViewMatrixAsLookAt( eye, center, up );
|
||||
up = Vec3d( 0.,0.,1. );
|
||||
right = Vec3d( 1.,0.,0. );
|
||||
//up.normalize();
|
||||
//right = (center-eye) ^ up;
|
||||
//right.normalize();
|
||||
|
||||
// projection matrix
|
||||
camera->getProjectionMatrixAsPerspective( fovy, aspectRatio, tmp, tmp );
|
||||
right *= aspectRatio;
|
||||
|
||||
} else {
|
||||
|
||||
// get POV-Ray camera setup from scene bounding sphere
|
||||
// constructed from bounding box
|
||||
// (bounding box computes model center more precisely than bounding sphere)
|
||||
ComputeBoundsVisitor cbVisitor;
|
||||
const_cast< Node& >( node ).accept( cbVisitor );
|
||||
BoundingBox &bb = cbVisitor.getBoundingBox();
|
||||
BoundingSphere bs( bb );
|
||||
|
||||
// set
|
||||
eye = bs.center() + Vec3( 0., -3.0 * bs.radius(), 0. );
|
||||
center = bs.center();
|
||||
up = Vec3d( 0.,1.,0. );
|
||||
right = Vec3d( 4./3.,0.,0. );
|
||||
|
||||
}
|
||||
|
||||
// camera
|
||||
fout << "camera { // following POV-Ray, x is right, y is up, and z is to the scene" << endl
|
||||
<< " location <" << eye[0] << ", " << eye[2] << ", " << eye[1] << ">" << endl
|
||||
<< " up <" << up[0] << ", " << up[2] << ", " << up[1] << ">" << endl
|
||||
<< " right <" << right[0] << ", " << right[2] << ", " << right[1] << ">" << endl
|
||||
<< " look_at <" << center[0] << ", " << center[2] << ", " << center[1] << ">" << endl
|
||||
<< "}" << endl
|
||||
<< endl;
|
||||
|
||||
POVWriterNodeVisitor povWriter( fout, node.getBound() );
|
||||
if( camera )
|
||||
|
||||
for( int i=0, c=camera->getNumChildren(); i<c; i++ )
|
||||
const_cast< Camera* >( camera )->getChild( i )->accept( povWriter );
|
||||
|
||||
else
|
||||
|
||||
const_cast< Node* >( &node )->accept( povWriter );
|
||||
|
||||
notify( NOTICE ) << "ReaderWriterPOV::writeNode() Done. ("
|
||||
<< povWriter.getNumProducedTriangles()
|
||||
<< " triangles written)" << endl;
|
||||
|
||||
return osgDB::ReaderWriter::WriteResult::FILE_SAVED;
|
||||
}
|
||||
|
||||
|
||||
osgDB::ReaderWriter::WriteResult
|
||||
ReaderWriterPOV::writeNode( const Node& node, const string& fileName,
|
||||
const osgDB::ReaderWriter::Options* options ) const
|
||||
{
|
||||
// accept extension
|
||||
string ext = osgDB::getLowerCaseFileExtension( fileName );
|
||||
if( !acceptsExtension( ext ) ) return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
notify( NOTICE ) << "ReaderWriterPOV::writeNode() Writing file "
|
||||
<< fileName.data() << endl;
|
||||
|
||||
osgDB::ofstream fout( fileName.c_str(), ios::out | ios::trunc );
|
||||
if( !fout )
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
else
|
||||
return writeNodeImplementation( node, fout, options );
|
||||
}
|
||||
|
||||
|
||||
osgDB::ReaderWriter::WriteResult
|
||||
ReaderWriterPOV::writeNode( const Node& node, ostream& fout,
|
||||
const osgDB::ReaderWriter::Options* options ) const
|
||||
{
|
||||
notify( osg::NOTICE ) << "ReaderWriterPOV::writeNode() Writing to "
|
||||
<< "stream" << endl;
|
||||
|
||||
return writeNodeImplementation( node, fout, options );
|
||||
}
|
||||
33
src/osgPlugins/pov/ReaderWriterPOV.h
Normal file
33
src/osgPlugins/pov/ReaderWriterPOV.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef READER_WRITER_POV_H
|
||||
#define READER_WRITER_POV_H
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/FileNameUtils>
|
||||
|
||||
|
||||
class ReaderWriterPOV : public osgDB::ReaderWriter
|
||||
{
|
||||
public:
|
||||
ReaderWriterPOV();
|
||||
|
||||
virtual const char* className() const
|
||||
{
|
||||
return "POV reader/writer";
|
||||
}
|
||||
|
||||
bool isInventorExtension( const std::string& extension ) const
|
||||
{
|
||||
return osgDB::equalCaseInsensitive( extension, "pov" ) ? true : false;
|
||||
}
|
||||
|
||||
virtual WriteResult writeNode( const osg::Node& node,
|
||||
const std::string& filename,
|
||||
const osgDB::ReaderWriter::Options* options = NULL) const;
|
||||
|
||||
virtual WriteResult writeNode( const osg::Node& node, std::ostream& fout,
|
||||
const Options* = NULL) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* READER_WRITER_POV_H */
|
||||
Reference in New Issue
Block a user