Commit ae918bfb authored by Dirk Wilden's avatar Dirk Wilden
Browse files

obj reader / writer plugin

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@8100 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 8f1d4e4d
include (plugin)
openflipper_plugin ()
This diff is collapsed.
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2009 by Computer Graphics Group, RWTH Aachen *
* www.openflipper.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenFlipper. *
* *
* OpenFlipper is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenFlipper 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 *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenFlipper. If not, *
* see <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 7918 $ *
* $Author: moebius $ *
* $Date: 2009-12-15 10:05:44 +0100 (Tue, 15 Dec 2009) $ *
* *
\*===========================================================================*/
#ifndef FILEOBJPLUGIN_HH
#define FILEOBJPLUGIN_HH
#include <QObject>
#include <OpenFlipper/common/Types.hh>
#include <OpenFlipper/BasePlugin/BaseInterface.hh>
#include <OpenFlipper/BasePlugin/FileInterface.hh>
#include <OpenFlipper/BasePlugin/LoadSaveInterface.hh>
#include <OpenFlipper/BasePlugin/LoggingInterface.hh>
#include <OpenFlipper/BasePlugin/ScriptInterface.hh>
#include <OpenFlipper/BasePlugin/INIInterface.hh>
#include <OpenFlipper/BasePlugin/TypeInterface.hh>
#include <OpenFlipper/BasePlugin/RPCInterface.hh>
#include <OpenFlipper/BasePlugin/StatusbarInterface.hh>
#include <OpenFlipper/BasePlugin/TextureInterface.hh>
#include <ObjectTypes/PolyMesh/PolyMesh.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
#include "OBJImporter.hh"
class FileOBJPlugin : public QObject, BaseInterface, FileInterface, LoadSaveInterface,
LoggingInterface, ScriptInterface, INIInterface, StatusbarInterface, RPCInterface, TextureInterface
{
Q_OBJECT
Q_INTERFACES(FileInterface)
Q_INTERFACES(LoadSaveInterface)
Q_INTERFACES(LoggingInterface)
Q_INTERFACES(BaseInterface)
Q_INTERFACES(ScriptInterface)
Q_INTERFACES(INIInterface)
Q_INTERFACES(StatusbarInterface)
Q_INTERFACES(RPCInterface)
Q_INTERFACES(TextureInterface)
signals:
void openedFile( int _id );
void addEmptyObject( DataType _type, int& _id);
void load(QString _filename, DataType _type, int& _id);
void save(int _id , QString _filename );
void log(Logtype _type, QString _message);
void log(QString _message);
void updateView();
void emptyObjectAdded( int _id );
void deleteObject( int _id );
// StatusbarInterface
void showStatusMessage(QString _message, int _timeout = 0);
void setStatus( ApplicationStatus::applicationStatus _status);
//RPCInterface
void pluginExists( QString _pluginName , bool& _exists );
//TextureInterface
void setTextureMode(QString _textureName, QString _mode, int _id );
void switchTexture( QString _textureName, int _id );
void addMultiTexture( QString _textureGroup, QString _name, QString _filename, int _id, int& _textureId);
private slots:
void fileOpened( int /*_id*/ ){};
void noguiSupported( ) {} ;
void initializePlugin();
/// Slot called when user wants to save the given Load options as default
void slotLoadDefault();
/// Slot called when user wants to save the given Save options as default
void slotSaveDefault();
public :
FileOBJPlugin();
~FileOBJPlugin() {};
QString name() { return (QString("FileOBJ")); };
QString description( ) { return (QString(tr("Load/Save OBJ-Files"))); };
DataType supportedType();
QString getSaveFilters();
QString getLoadFilters();
QWidget* saveOptionsWidget(QString /*_currentFilter*/);
QWidget* loadOptionsWidget(QString /*_currentFilter*/);
public slots:
/// Loads Object and converts it to a triangle mesh if possible
int loadObject(QString _filename);
bool saveObject(int _id, QString _filename);
/// Loads a triangle mesh
int loadTriMeshObject(QString _filename);
/// Loads a poly mesh
int loadPolyMeshObject(QString _filename);
QString version() { return QString("1.0"); };
private:
/// Reader functions
void checkTypes(QString _filename, OBJImporter& _importer);
bool readMaterial(QString _filename, OBJImporter& _importer);
void readOBJFile(QString _filename, OBJImporter& _importer);
void addNewObject(OBJImporter& _importer, QString _name );
void addTextures(OBJImporter& _importer, int _objectID );
private :
///TODO replace by real materials
std::vector< OpenMesh::Vec4f > materials_;
int getMaterial(OpenMesh::Vec4f _color);
///writer functions
template< class MeshT >
bool writeMaterial(QString _filename, MeshT& _mesh );
template< class MeshT >
bool writeMesh(std::ostream& _out, QString _filename, MeshT& _mesh );
private:
//Option Widgets
QWidget* loadOptions_;
QWidget* saveOptions_;
QCheckBox* saveBinary_;
QCheckBox* saveVertexColor_;
QCheckBox* saveFaceColor_;
QCheckBox* saveAlpha_;
QCheckBox* saveNormals_;
QCheckBox* saveTexCoords_;
QPushButton* saveDefaultButton_;
QComboBox* triMeshHandling_;
QCheckBox* loadVertexColor_;
QCheckBox* loadFaceColor_;
QCheckBox* loadAlpha_;
QCheckBox* loadNormals_;
QCheckBox* loadTexCoords_;
QPushButton* loadDefaultButton_;
bool forceTriangleMesh_;
bool forcePolyMesh_;
};
#if defined(INCLUDE_TEMPLATES) && !defined(FILEOBJPLUGIN_C)
#define FILEOBJPLUGIN_TEMPLATES
#include "FileOBJT.cc"
#endif
#endif //FILEOBJPLUGIN_HH
#define FILEOBJPLUGIN_C
#include "FileOBJ.hh"
#include <OpenMesh/Core/Utils/color_cast.hh>
#include <OpenMesh/Core/Geometry/VectorT.hh>
//-----------------------------------------------------------------------------------------------------
template< class MeshT >
bool FileOBJPlugin::writeMaterial(QString _filename, MeshT& _mesh )
{
bool optionColorAlpha = false;
// check options
if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0)
optionColorAlpha = saveAlpha_->isChecked();
std::fstream matStream( _filename.toStdString().c_str(), std::ios_base::out );
if ( !matStream ){
emit log(LOGERR, tr("writeMaterial : cannot not open file %1").arg(_filename) );
return false;
}
OpenMesh::Vec4f c;
materials_.clear();
//iterate over faces
typename MeshT::FaceIter f_it;
typename MeshT::FaceIter f_end = _mesh.faces_end();
for (f_it = _mesh.faces_begin(); f_it != f_end; ++f_it){
c = OpenMesh::color_cast<OpenMesh::Vec4f> (_mesh.color( f_it.handle() ));
getMaterial(c);
}
//write the materials
if ( optionColorAlpha )
for (uint i=0; i < materials_.size(); i++){
matStream << "newmtl " << "mat" << i << std::endl;
matStream << "Ka 0.5000 0.5000 0.5000" << std::endl;
matStream << "Kd " << materials_[i][0] << materials_[i][1] << materials_[i][2] << std::endl;
matStream << "Tr " << materials_[i][3] << std::endl;
matStream << "illum 1" << std::endl;
}
else
for (uint i=0; i < materials_.size(); i++){
matStream << "newmtl " << "mat" << i << std::endl;
matStream << "Ka 0.5000 0.5000 0.5000" << std::endl;
matStream << "Kd " << materials_[i][0] << materials_[i][1] << materials_[i][2] << std::endl;
matStream << "illum 1" << std::endl;
}
matStream.close();
return true;
}
//-----------------------------------------------------------------------------------------------------
template< class MeshT >
bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, MeshT& _mesh ){
unsigned int i, j, nV, nF, idx;
Vec3f v, n;
Vec2f t;
typename MeshT::VertexHandle vh;
std::vector<typename MeshT::VertexHandle> vhandles;
bool useMatrial = false;
OpenMesh::Vec4f c;
bool optionFaceColors = false;
bool optionVertexNormals = false;
bool optionVertexTexCoords = false;
bool optionColorAlpha = false;
QFileInfo fi(_filename);
// check options
if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0){
optionFaceColors = saveFaceColor_->isChecked();
optionVertexNormals = saveNormals_->isChecked();
optionVertexTexCoords = saveTexCoords_->isChecked();
optionColorAlpha = saveAlpha_->isChecked();
}
//create material file if needed
if ( optionFaceColors ){
QString matFile = fi.absolutePath() + QDir::separator() + fi.baseName() + ".mat";
useMatrial = writeMaterial(matFile, _mesh);
}
// header
_out << "# " << _mesh.n_vertices() << " vertices, ";
_out << _mesh.n_faces() << " faces" << std::endl;
// material file
if (useMatrial && optionFaceColors )
_out << "mtllib " << fi.baseName().toStdString() << ".mat" << std::endl;
// vertex data (point, normals, texcoords)
for (i=0, nV=_mesh.n_vertices(); i<nV; ++i)
{
vh = typename MeshT::VertexHandle(i);
v = _mesh.point(vh);
n = _mesh.normal(vh);
t = _mesh.texcoord2D(vh);
_out << "v " << v[0] <<" "<< v[1] <<" "<< v[2] << std::endl;
if ( optionVertexNormals )
_out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << std::endl;
if ( optionVertexTexCoords )
_out << "vt " << t[0] <<" "<< t[1] << std::endl;
}
int lastMat = -1;
// faces (indices starting at 1 not 0)
typename MeshT::FaceIter f_it;
typename MeshT::FaceIter f_end = _mesh.faces_end();
for (f_it = _mesh.faces_begin(); f_it != f_end; ++f_it){
if (useMatrial && optionFaceColors ){
int material = -1;
c = OpenMesh::color_cast<OpenMesh::Vec4f> (_mesh.color( f_it.handle() ));
material = getMaterial(c);
// if we are ina a new material block, specify in the file which material to use
if(lastMat != material) {
_out << "usemtl mat" << material << std::endl;
lastMat = material;
}
}
_out << "f";
typename MeshT::FaceVertexIter fv_it;
for (fv_it=_mesh.fv_iter(f_it); fv_it; ++fv_it){
// Write vertex index
idx = fv_it.handle().idx() + 1;
_out << " " << idx;
// write separator
_out << "/" ;
// write vertex texture coordinate index
if ( optionVertexTexCoords )
_out << idx;
// write separator
_out << "/" ;
// write vertex normal index
if ( optionVertexNormals )
_out << idx;
}
_out << std::endl;
}
materials_.clear();
return true;
}
\ No newline at end of file
#ifndef DOXY_IGNORE_THIS
typedef OpenMesh::Vec3f Vec3f;
class Material
{
public:
Material() { cleanup(); }
void cleanup()
{
Kd_is_set_ = false;
Ka_is_set_ = false;
Ks_is_set_ = false;
Tr_is_set_ = false;
map_Kd_is_set_ = false;
}
bool is_valid(void) const
{ return Kd_is_set_ || Ka_is_set_ || Ks_is_set_ || Tr_is_set_; }
bool has_Kd(void) { return Kd_is_set_; }
bool has_Ka(void) { return Ka_is_set_; }
bool has_Ks(void) { return Ks_is_set_; }
bool has_Tr(void) { return Tr_is_set_; }
bool has_map_Kd(void) { return map_Kd_is_set_; }
void set_Kd( float r, float g, float b )
{ Kd_=Vec3f(r,g,b); Kd_is_set_=true; }
void set_Ka( float r, float g, float b )
{ Ka_=Vec3f(r,g,b); Ka_is_set_=true; }
void set_Ks( float r, float g, float b )
{ Ks_=Vec3f(r,g,b); Ks_is_set_=true; }
void set_Tr( float t )
{ Tr_=t; Tr_is_set_=true; }
void set_map_Kd( std::string _name, int _index_Kd )
{ map_Kd_ = _name, index_Kd_ = _index_Kd; map_Kd_is_set_ = true; };
const Vec3f& Kd( void ) const { return Kd_; }
const Vec3f& Ka( void ) const { return Ka_; }
const Vec3f& Ks( void ) const { return Ks_; }
float Tr( void ) const { return Tr_; }
const std::string& map_Kd( void ) { return map_Kd_ ; }
const int& map_Kd_index( void ) { return index_Kd_ ; }
private:
Vec3f Kd_; bool Kd_is_set_; // diffuse
Vec3f Ka_; bool Ka_is_set_; // ambient
Vec3f Ks_; bool Ks_is_set_; // specular
float Tr_; bool Tr_is_set_; // transperency
std::string map_Kd_; int index_Kd_; bool map_Kd_is_set_; // Texture
};
typedef std::map<std::string, Material> MaterialList;
#endif
#include "OBJImporter.hh"
#include <OpenMesh/Core/Utils/vector_cast.hh>
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// base class needs virtual destructor
OBJImporter::~OBJImporter(){
}
//-----------------------------------------------------------------------------
/// add a vertex with coordinate \c _point
VertexHandle OBJImporter::addVertex(const Vec3f& _point){
vertices_.push_back( _point );
return vertices_.size()-1;
}
//-----------------------------------------------------------------------------
/// add texture coordinates
int OBJImporter::addTexCoord(const Vec2f& _coord){
texCoords_.push_back( _coord );
return texCoords_.size()-1;
}
//-----------------------------------------------------------------------------
/// add a normal
int OBJImporter::addNormal(const Vec3f& _normal){
normals_.push_back( _normal );
return normals_.size()-1;
}
//-----------------------------------------------------------------------------
/// add a mesh
void OBJImporter::addObject( BaseObject* _object ){
PolyMeshObject* polyMeshObj = dynamic_cast< PolyMeshObject* > (_object);
TriMeshObject* triMeshObj = dynamic_cast< TriMeshObject* > (_object);
if ( polyMeshObj ){
polyMeshes_.push_back( polyMeshObj->mesh() );
objects_.push_back( _object );
} else if ( triMeshObj ){
triMeshes_.push_back( triMeshObj->mesh() );
objects_.push_back( _object );
} else {
std::cerr << "Error: Cannot add object. Type is unknown!" << std::endl;
}
}
//-----------------------------------------------------------------------------
/// get id of the active object
int OBJImporter::currentObject(){
return objects_.size()-1;
}
//-----------------------------------------------------------------------------
/// get the active polyMesh
PolyMesh* OBJImporter::currentPolyMesh(){
if (polyMeshes_.size() == 0)
return 0;
else
return polyMeshes_.back();
}
//-----------------------------------------------------------------------------
/// get the active triMesh
TriMesh* OBJImporter::currentTriMesh(){
if (triMeshes_.size() == 0)
return 0;
else
return triMeshes_.back();
}
//-----------------------------------------------------------------------------
/// check if the vertex of a face is already added to the mesh. if not add it.
void OBJImporter::checkExistance(VertexHandle _vh){
if ( isTriangleMesh( currentObject() ) ){
//handle triangle meshes
if ( !currentTriMesh() ) return;
if ( _vh >= (int)vertices_.size() ){
std::cerr << "Error: Vertex ID too large" << std::endl;
return;
}
if ( vertexMapTri_.find( _vh ) == vertexMapTri_.end() )
vertexMapTri_[ _vh ] = currentTriMesh()->add_vertex( (TriMesh::Point) vertices_[_vh] );
} else if ( isPolyMesh( currentObject() ) ){
//handle poly meshes
if ( !currentPolyMesh() ) return;
if ( _vh >= (int)vertices_.size() ){
std::cerr << "Error: Vertex ID too large" << std::endl;
return;
}
if ( vertexMapPoly_.find( _vh ) == vertexMapPoly_.end() )
vertexMapPoly_[ _vh ] = currentPolyMesh()->add_vertex( (PolyMesh::Point) vertices_[_vh] );
}
}
//-----------------------------------------------------------------------------
/// set vertex texture coordinate
void OBJImporter::setVertexTexCoord(VertexHandle _vh, int _texCoordID){
if ( isTriangleMesh( currentObject() ) ){
//handle triangle meshes
if ( !currentTriMesh() ) return;
if ( _texCoordID < (int) texCoords_.size() ){
if ( vertexMapTri_.find( _vh ) != vertexMapTri_.end() )
currentTriMesh()->set_texcoord2D( vertexMapTri_[_vh], texCoords_[ _texCoordID ] );
}else{
std::cerr << "Error: TexCoord ID too large" << std::endl;
}
} else if ( isPolyMesh( currentObject() ) ){
//handle poly meshes
if ( !currentPolyMesh() ) return;
if ( _texCoordID < (int) texCoords_.size() ){
if ( vertexMapPoly_.find( _vh ) != vertexMapPoly_.end() )
currentPolyMesh()->set_texcoord2D( vertexMapPoly_[_vh], texCoords_[ _texCoordID ] );