Files
OpenSceneGraph/src/osgPlugins/vrml/ConvertToVRML.cpp
2012-03-21 17:36:20 +00:00

1304 lines
43 KiB
C++

/*
*
* OSG to VRML2 converter for OpenSceneGraph.
*
* authors :
* Johan Nouvel (johan_nouvel@yahoo.com)
*
*
*/
#include "ConvertToVRML.h"
#include <iostream>
#include <string.h>
#include <limits>
#include <osg/Quat>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/StateSet>
#include <osg/TexGen>
#include <osg/TexEnv>
#include <osg/BoundingSphere>
#include <osgDB/WriteFile>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osg/Image>
using namespace std;
/////////////////////////////////////////////////////////////////////////
//
// transformNode
//
/////////////////////////////////////////////////////////////////////////
osg::Node* transformNode(const osg::Node& root) {
// create a zup to yup OSG Matrix
osg::MatrixTransform* ret = new osg::MatrixTransform();
osg::Matrix osgToVRMLMat(osg::Matrix(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
ret->setDataVariance(osg::Object::STATIC);
ret->setMatrix(osgToVRMLMat);
if (strcmp(root.className(), "MatrixTransform") == 0) {
const osg::MatrixTransform& aMat = static_cast<const osg::MatrixTransform&> (root);
osg::MatrixTransform* node = new osg::MatrixTransform(aMat);
ret->addChild(node);
} else if (strcmp(root.className(), "Group") == 0) {
const osg::Group& aGroup = static_cast<const osg::Group&> (root);
osg::Group* node = new osg::Group(aGroup);
ret->addChild(node);
} else if (strcmp(root.className(), "PositionAttitudeTransform") == 0) {
const osg::PositionAttitudeTransform& aPAT = static_cast<const osg::PositionAttitudeTransform&> (root);
osg::PositionAttitudeTransform* node = new osg::PositionAttitudeTransform(aPAT);
ret->addChild(node);
} else if (strcmp(root.className(), "Geode") == 0) {
const osg::Geode& aGeode = static_cast<const osg::Geode&> (root);
osg::Geode* node = new osg::Geode(aGeode);
ret->addChild(node);
} else {
osg::notify(osg::ALWAYS) << root.className() << " unsupported" << endl;
}
if (ret->getNumChildren() > 0) {
return ret;
}
return (NULL);
}
/////////////////////////////////////////////////////////////////////////
//
// convertToVRML
//
/////////////////////////////////////////////////////////////////////////
osgDB::ReaderWriter::WriteResult convertToVRML(const osg::Node& root, const std::string& filename, const osgDB::ReaderWriter::Options* options) {
ToVRML toVrml(filename, options);
//cout << root.className() << endl;
osg::Node* aRoot = transformNode(root);
if (aRoot == NULL) {
return (osgDB::ReaderWriter::WriteResult(osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED));
}
aRoot->accept(toVrml);
return (toVrml.result());
}
/////////////////////////////////////////////////////////////////////////
//
// ToVRML
//
/////////////////////////////////////////////////////////////////////////
ToVRML::ToVRML(const std::string& fileName, const osgDB::ReaderWriter::Options* options) :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {
_fout.open(fileName.c_str(), ios::out);
if (!_fout) {
_res = osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED;
return;
}
_res = osgDB::ReaderWriter::WriteResult::FILE_SAVED;
_pathToOutput = osgDB::getFilePath(fileName.c_str());
if (_pathToOutput == "") {
_pathToOutput = ".";
}
//std::cout<<" path -"<<_pathToOutput<<"-"<<std::endl;
_fout.precision(6);
_fout.setf(ios::fixed, ios::floatfield);
_strIndent = (char*) malloc(33);
for (int i = 0; i < 33; i++) {
_strIndent[i] = ' ';
}
_indent = 0;
_strIndent[0] = '\0';
//initialize
_fout << "#VRML V2.0 utf8\n\n";
_textureMode = CONVERT_TEXTURE;
_txtUnit = 0;
//_convertTextures = true;
_pathRelativeToOutput = ".";
if (options != NULL) {
std::string opt = options->getOptionString();
if (opt.find("convertTextures=0") != std::string::npos) {
//std::cout << "Read XML stream" << std::endl;
_textureMode = COPY_TEXTURE;
} else if (opt.find("convertTextures=-1") != std::string::npos) {
_textureMode = KEEP_ORIGINAL_TEXTURE;
} else if (opt.find("convertTextures=-2") != std::string::npos) {
_textureMode = NO_TEXTURE;
} else if (opt.find("convertTextures=-3") != std::string::npos) {
_textureMode = CONVERT_TEXTURE;
}
if (opt.find("directoryTextures=") != std::string::npos) {
std::string dirOpt = opt;
dirOpt.erase(0, dirOpt.find("directoryTextures=") + 18);
_pathRelativeToOutput = dirOpt.substr(0, dirOpt.find(' '));
}
if (opt.find("textureUnit=") != std::string::npos) {
std::string dirOpt = opt;
dirOpt.erase(0, dirOpt.find("textureUnit=") + 12);
_txtUnit = atoi(dirOpt.substr(0, dirOpt.find(' ')).c_str());
}
}
if (_textureMode != NO_TEXTURE) {
_defaultImage = new osg::Image();
_defaultImage->setFileName(_pathToOutput + "/" + _pathRelativeToOutput + "/default_texture.png");
int s = 1;
int t = 1;
unsigned char *data = new unsigned char[s * t * 3];
data[0] = 255;
data[1] = 255;
data[2] = 255;
_defaultImage->setImage(s, t, 0, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
osgDB::writeImageFile(*(_defaultImage.get()), _defaultImage->getFileName());
}
}
/////////////////////////////////////////////////////////////////////////
//
// ~ToVRML
//
/////////////////////////////////////////////////////////////////////////
ToVRML::~ToVRML() {
if (_fout) {
_fout.close();
}
free( _strIndent);
}
/////////////////////////////////////////////////////////////////////////
//
// indent
//
/////////////////////////////////////////////////////////////////////////
char* ToVRML::indent() {
return (_strIndent);
}
/////////////////////////////////////////////////////////////////////////
//
// indentM
//
/////////////////////////////////////////////////////////////////////////
char* ToVRML::indentM() {
_strIndent[_indent] = ' ';
_indent += 2;
if (_indent > 32) {
_indent = 32;
}
_strIndent[_indent] = '\0';
return (_strIndent);
}
/////////////////////////////////////////////////////////////////////////
//
// indentL
//
/////////////////////////////////////////////////////////////////////////
char* ToVRML::indentL() {
_strIndent[_indent] = ' ';
_indent -= 2;
if (_indent < 0) {
_indent = 0;
}
_strIndent[_indent] = '\0';
return (_strIndent);
}
/////////////////////////////////////////////////////////////////////////
//
// apply(osg::Geode)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::Geode& node) {
//cout << "Geode" << endl;
pushStateSetStack(node.getStateSet());
for (unsigned int i = 0; i < node.getNumDrawables(); i++) {
apply(node.getDrawable(i));
}
popStateSetStack();
}
/////////////////////////////////////////////////////////////////////////
//
// apply
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::Drawable* drawable) {
// get the drawable type
//cout<<"ICI "<<drawable->className()<<endl;
pushStateSetStack(drawable->getStateSet());
if (strcmp(drawable->className(), "Geometry") == 0) {
apply(drawable->asGeometry());
} else {
osg::notify(osg::ALWAYS) << "Drawable " << drawable->className() << " unsupported" << endl;
}
popStateSetStack();
}
/////////////////////////////////////////////////////////////////////////
//
// apply
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::Geometry* geom) {
// are all primitives faces or line ?
GLenum mode;
osg::PrimitiveSet::Type type;
_fout << indent() << "Shape {\n";
indentM();
writeAppearance( getCurrentStateSet());
indentL();
int modePoints = 0;
int modeLines = 0;
int modeFaces = 0;
for (unsigned int p = 0; p < geom->getNumPrimitiveSets(); p++) {
mode = geom->getPrimitiveSet(p)->getMode();
if (mode == osg::PrimitiveSet::POINTS) {
modePoints++;
} else if ((mode == osg::PrimitiveSet::LINES) || (mode == osg::PrimitiveSet::LINE_STRIP) || (mode == osg::PrimitiveSet::LINE_LOOP)) {
modeLines++;
} else if ((mode == osg::PrimitiveSet::TRIANGLES) || (mode == osg::PrimitiveSet::TRIANGLE_STRIP) || (mode == osg::PrimitiveSet::TRIANGLE_FAN) || (mode
== osg::PrimitiveSet::QUADS) || (mode == osg::PrimitiveSet::QUAD_STRIP) || (mode == osg::PrimitiveSet::POLYGON)) {
modeFaces++;
}
}
//std::cout << "primitives type : Points " << modePoints << " Line " << modeLines << " Face " << modeFaces << std::endl;
if (modePoints > 0) {
_fout << indentM() << "geometry PointSet {\n";
for (unsigned int p = 0; p < geom->getNumPrimitiveSets(); p++) {
mode = geom->getPrimitiveSet(p)->getMode();
type = geom->getPrimitiveSet(p)->getType();
if (mode == osg::PrimitiveSet::POINTS) {
osg::notify(osg::WARN) << " osg::PrimitiveSetMode = POINTS not supported by VRML Writer" << std::endl;
}
}
}
if (modeLines > 0) {
_fout << indentM() << "geometry IndexedLineSet {\n";
for (unsigned int p = 0; p < geom->getNumPrimitiveSets(); p++) {
mode = geom->getPrimitiveSet(p)->getMode();
type = geom->getPrimitiveSet(p)->getType();
if ((mode == osg::PrimitiveSet::LINES) || (mode == osg::PrimitiveSet::LINE_STRIP) || (mode == osg::PrimitiveSet::LINE_LOOP)) {
osg::notify(osg::WARN) << " osg::PrimitiveSetMode = LINES, LINE_STRIP or LINE_LOOP not supported by VRML Writer" << std::endl;
}
}
}
if (modeFaces > 0) {
_fout << indentM() << "geometry IndexedFaceSet {\n";
_fout << indentM() << "solid FALSE\n";
indentL();
_fout << indentM() << "coordIndex [\n";
indentM();
std::vector<int> primitiveSetFaces;
int primitiveFaces = 0;
for (unsigned int p = 0; p < geom->getNumPrimitiveSets(); p++) {
mode = geom->getPrimitiveSet(p)->getMode();
type = geom->getPrimitiveSet(p)->getType();
if ((mode == osg::PrimitiveSet::TRIANGLES) || (mode == osg::PrimitiveSet::TRIANGLE_STRIP) || (mode == osg::PrimitiveSet::TRIANGLE_FAN) || (mode == osg::PrimitiveSet::QUADS)
|| (mode == osg::PrimitiveSet::QUAD_STRIP) || (mode == osg::PrimitiveSet::POLYGON)) {
if (type == osg::PrimitiveSet::PrimitiveType) {
osg::notify(osg::WARN) << "osg::PrimitiveSet::PrimitiveType not supported by VRML Writer" << std::endl;
} else if (type == osg::PrimitiveSet::DrawArraysPrimitiveType) {
//std::cout << "osg::PrimitiveSet::DrawArraysPrimitiveType" << std::endl;
osg::ref_ptr < osg::DrawArrays > dra = dynamic_cast<osg::DrawArrays*> (geom->getPrimitiveSet(p));
unsigned int* indices = new unsigned int[dra->getCount()];
for (int j = 0; j < dra->getCount(); j++) {
indices[j] = dra->getFirst() + j;
}
writeCoordIndex(mode, indices, dra->getCount(), primitiveSetFaces, primitiveFaces);
delete[] indices;
} else if (type == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) {
//osg::notify(osg::WARN) << " osg::PrimitiveSet::DrawArrayLengthsPrimitiveType not supported by VRML Writer" << std::endl;
osg::ref_ptr < osg::DrawArrayLengths > dal = dynamic_cast<osg::DrawArrayLengths*> (geom->getPrimitiveSet(p));
//std::cout<<dal->getFirst()<<" "<<dal->getNumPrimitives()<<" "<< dal->getNumIndices ()<<" "<< dal->getNumInstances()<<std::endl;
int first = 0;
for (unsigned int prim = dal->getFirst(); prim < dal->getNumPrimitives(); prim++) {
//std::cout<<(*dal)[prim]<<std::endl;
unsigned int numIndices = (*dal)[prim];
unsigned int * indices = new unsigned int[numIndices];
for (unsigned int i = 0; i < numIndices; i++) {
indices[i] = first + i;
}
first += (*dal)[prim];
// write coorIndex as if wa have an indexed geometry
writeCoordIndex(mode, indices, numIndices, primitiveSetFaces, primitiveFaces);
delete[] indices;
}
} else if (type == osg::PrimitiveSet::DrawElementsUBytePrimitiveType) {
//std::cout << "osg::PrimitiveSet::DrawElementsUBytePrimitiveType" << std::endl;
osg::ref_ptr < osg::DrawElementsUByte > drui = dynamic_cast<osg::DrawElementsUByte*> (geom->getPrimitiveSet(p));
const unsigned char * indices = (const unsigned char*) (drui->getDataPointer());
writeCoordIndex(mode, indices, drui->getNumIndices(), primitiveSetFaces, primitiveFaces);
} else if (type == osg::PrimitiveSet::DrawElementsUShortPrimitiveType) {
//std::cout << "osg::PrimitiveSet::DrawElementsUShortPrimitiveType" << std::endl;
osg::ref_ptr < osg::DrawElementsUShort > drui = dynamic_cast<osg::DrawElementsUShort*> (geom->getPrimitiveSet(p));
const unsigned short * indices = (const unsigned short*) (drui->getDataPointer());
writeCoordIndex(mode, indices, drui->getNumIndices(), primitiveSetFaces, primitiveFaces);
} else if (type == osg::PrimitiveSet::DrawElementsUIntPrimitiveType) {
//std::cout << "osg::PrimitiveSet::DrawElementsUIntPrimitiveType" << std::endl;
osg::ref_ptr < osg::DrawElementsUInt > drui = dynamic_cast<osg::DrawElementsUInt*> (geom->getPrimitiveSet(p));
const unsigned int * indices = (const unsigned int*) (drui->getDataPointer());
writeCoordIndex(mode, indices, drui->getNumIndices(), primitiveSetFaces, primitiveFaces);
}
}
}
_fout << indentL() << "]\n";
indentL();
//write vertex
writeCoord((osg::Vec3Array*) (geom->getVertexArray()));
//write texture coordinate
if (_textureMode != NO_TEXTURE) {
writeTexCoord((osg::Vec2Array*) (geom->getTexCoordArray(_txtUnit)), (osg::Vec3Array*) (geom->getVertexArray()));
}
//write normals
writeNormal(geom, primitiveSetFaces, primitiveFaces);
//write colors
writeColor(geom, primitiveSetFaces, primitiveFaces);
}
_fout << indent() << "}\n";
_fout << indentL() << "}\n";
}
/////////////////////////////////////////////////////////////////////////
//
// writeAppearance
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::writeAppearance(osg::StateSet* stateset) {
if (stateset == NULL) {
return;
}
osg::ref_ptr < osg::StateSet > ss = stateset;
_fout << indent() << "appearance Appearance {\n";
osg::Material* mat = (osg::Material*) (ss->getAttribute(osg::StateAttribute::MATERIAL));
osg::Texture2D* tex;
if (_textureMode == NO_TEXTURE) {
tex = NULL;
} else {
tex = (osg::Texture2D*) (ss->getTextureAttribute(_txtUnit, osg::StateAttribute::TEXTURE));
}
if (mat) {
bool alreadyLoaded;
std::string name;
osg::Vec4 ambient, diffuse, specular, emission;
float shininess;
ambient = mat->getAmbient(osg::Material::FRONT);
diffuse = mat->getDiffuse(osg::Material::FRONT);
specular = mat->getSpecular(osg::Material::FRONT);
shininess = mat->getShininess(osg::Material::FRONT);
emission = mat->getEmission(osg::Material::FRONT);
float transp = 1 - (ambient[3] + diffuse[3] + specular[3] + emission[3]) / 4.0;
if (transp < 0)
transp = 0;
//if (transp == 0 && tex) {
// if (tex->getImage()->isImageTranslucent()) {
// transp = 0.01;
// mat->setTransparency(osg::Material::FRONT,transp);
// }
//}
findMaterialName(mat, name, alreadyLoaded);
if (alreadyLoaded) {
_fout << indentM() << "material USE " << name << "\n";
indentL();
} else {
_fout << indentM() << "material DEF " << name << " Material {\n";
//_fout << indentM() << "material Material {\n";
_fout << indentM() << "diffuseColor " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
_fout << indent() << "emissiveColor " << emission[0] << " " << emission[1] << " " << emission[2] << "\n";
_fout << indent() << "specularColor " << specular[0] << " " << specular[1] << " " << specular[2] << "\n";
_fout << indent() << "shininess " << shininess << "\n";
float ambientI = (ambient[0] + ambient[1] + ambient[2]) / 3.0;
if (ambientI > 1)
ambientI = 1;
_fout << indent() << "ambientIntensity " << ambientI << "\n";
_fout << indent() << "transparency " << transp << "\n";
_fout << indentL() << "}\n";
indentL();
}
}
if (tex) {
bool alreadyLoaded;
std::string name;
findTextureName(tex, name, alreadyLoaded);
if (alreadyLoaded) {
_fout << indentM() << "texture USE " << name << "\n";
indentL();
} else {
_fout << indentM() << "texture DEF " << name << " ImageTexture {\n";
std::string texName = tex->getImage()->getFileName();
if (_textureMode == COPY_TEXTURE || _textureMode == CONVERT_TEXTURE) {
texName = _pathRelativeToOutput + "/" + osgDB::getSimpleFileName(texName);
} else if (_textureMode == KEEP_ORIGINAL_TEXTURE) {
texName = _pathRelativeToOutput + "/" + texName;
}
_fout << indentM() << "url [ \"" << texName << "\" ]\n";
//std::cout<<"WRAP "<<tex->getWrap(osg::Texture::WRAP_S)<<std::endl;
if (tex->getWrap(osg::Texture::WRAP_S) == osg::Texture::REPEAT) {
_fout << indent() << "repeatS TRUE\n";
} else {
_fout << indent() << "repeatS FALSE\n";
}
if (tex->getWrap(osg::Texture::WRAP_T) == osg::Texture::REPEAT) {
_fout << indent() << "repeatT TRUE\n";
} else {
_fout << indent() << "repeatT FALSE\n";
}
_fout << indentL() << "}\n";
indentL();
}
}
_fout << indent() << "}\n";
}
/////////////////////////////////////////////////////////////////////////
//
// apply(osg::Group)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::Group& node) {
//cout << "Group" << endl;
_fout << indent() << "Group {\n";
_fout << indentM() << "children [\n";
pushStateSetStack(node.getStateSet());
indentM();
traverse(node);
indentL();
popStateSetStack();
_fout << indent() << "]\n";
_fout << indentL() << "}\n";
}
/////////////////////////////////////////////////////////////////////////
//
// apply(osg::MatrixTransform)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::MatrixTransform& node) {
//cout << "MatrixTransform" << endl;
osg::Matrixf mat = node.getMatrix();
// for(int i=0;i<16;i++){
// cout <<mat.ptr()[i]<<" ";
// }
// cout<<endl;
osg::Vec3 trans = mat.getTrans();
osg::Vec3 scale = mat.getScale();
osg::Quat quat;
mat.get(quat);
double angle;
osg::Vec3 axe;
quat.getRotate(angle, axe);
_fout << indent() << "Transform {\n";
_fout << indentM() << "scale " << scale[0] << " " << scale[1] << " " << scale[2] << "\n";
//_fout << indentM() << "scale 1 1 1\n";
_fout << indent() << "translation " << trans[0] << " " << trans[1] << " " << trans[2] << "\n";
_fout << indent() << "rotation " << axe[0] << " " << axe[1] << " " << axe[2] << " " << angle << "\n";
_fout << indent() << "children [\n";
pushStateSetStack(node.getStateSet());
indentM();
traverse(node);
indentL();
popStateSetStack();
_fout << indent() << "]\n";
_fout << indentL() << "}\n";
}
/////////////////////////////////////////////////////////////////////////
//
// apply(osg::PositionAttitudeTransform)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::PositionAttitudeTransform& node) {
osg::Vec3 trans = node.getPosition();
osg::Vec3 scale = node.getScale();
osg::Quat quat = node.getAttitude();
double angle;
osg::Vec3 axe;
quat.getRotate(angle, axe);
_fout << indent() << "Transform {\n";
_fout << indentM() << "scale " << scale[0] << " " << scale[1] << " " << scale[2] << "\n";
//_fout << indentM() << "scale 1 1 1\n";
_fout << indent() << "translation " << trans[0] << " " << trans[1] << " " << trans[2] << "\n";
_fout << indent() << "rotation " << axe[0] << " " << axe[1] << " " << axe[2] << " " << angle << "\n";
_fout << indent() << "children [\n";
pushStateSetStack(node.getStateSet());
indentM();
traverse(node);
indentL();
popStateSetStack();
_fout << indent() << "]\n";
_fout << indentL() << "}\n";
}
////////////////////////////////////////////////////////////////////////
//
// apply(osg::Billboard)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::Billboard& node) {
osg::notify(osg::ALWAYS) << "WARNING : Billboard is changed to Group" << endl;
_fout << indent() << "Group {\n";
indentM();
//osg::Billboard::Mode mode = node.getMode();
//const osg::Vec3 axe = node.getAxis();
//const osg::Vec3 normal = node.getNormal();
//if (mode == osg::Billboard::AXIAL_ROT) {
// _fout << indent() << "axisOfRotation " << axe[0] << " " << axe[1] << " " << axe[2] << "\n";
//}
//osg::BoundingSphere sph=node.getBound();
//_fout << indent() << "bboxCenter "<<sph.center()[0]<<" "<<sph.center()[1]<<" "<<sph.center()[2]<<"\n";
//_fout << indent() << "bboxSize "<<sph.radius()<<" "<<sph.radius()<<" "<<sph.radius()<<"\n";
_fout << indent() << "children [\n";
pushStateSetStack(node.getStateSet());
indentM();
for (unsigned int i = 0; i < node.getNumDrawables(); i++) {
osg::Vec3 trans = node.getPosition(i);
_fout << indent() << "Transform {\n";
_fout << indentM() << "translation " << trans[0] << " " << trans[1] << " " << trans[2] << "\n";
_fout << indent() << "children [\n";
indentM();
apply(node.getDrawable(i));
_fout << indentL() << "]\n";
_fout << indentL() << "}\n";
}
popStateSetStack();
_fout << indentL() << "]\n";
_fout << indentL() << "}\n";
}
////////////////////////////////////////////////////////////////////////
//
// apply(osg::LOD)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::LOD& node) {
//std::cout << "LOD" << endl;
_fout << indent() << "LOD {\n";
bool fakeFirst = false;
bool fakeLast = false;
if (node.getMinRange(0) > 0) {
fakeFirst = true;
}
if (node.getMaxRange(node.getNumRanges() - 1) < std::numeric_limits<float>::max()) {
fakeLast = true;
}
_fout << indentM() << "level [\n";
if (fakeFirst) {
_fout << indentM() << "Shape {\n";
_fout << indent() << "}\n";
indentL();
}
pushStateSetStack(node.getStateSet());
indentM();
traverse(node);
indentL();
popStateSetStack();
if (fakeLast) {
_fout << indentM() << "Shape {\n";
_fout << indent() << "}\n";
indentL();
}
_fout << indent() << "]\n";
osg::Vec3 center;
if (node.getCenterMode() == osg::LOD::USER_DEFINED_CENTER) {
center = node.getCenter();
} else {
center = node.getBound().center();
}
_fout << indent() << "center " << center[0] << " " << center[1] << " " << center[2] << "\n";
_fout << indentM() << "range [";
if (fakeFirst) {
_fout << indentM() << node.getMinRange(0) << ",";
}
for (unsigned int i = 0; i < node.getNumRanges(); i++) {
_fout << indentM() << node.getMaxRange(i);
if (i < node.getNumRanges() - 1) {
_fout << ",";
}
}
_fout << "]\n";
_fout << indentL() << "}\n";
}
/////////////////////////////////////////////////////////////////////////
//
// apply(osg::Node)
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::apply(osg::Node& node) {
osg::notify(osg::ALWAYS) << node.className() << " not supported" << endl;
pushStateSetStack(node.getStateSet());
traverse(node);
popStateSetStack();
}
/////////////////////////////////////////////////////////////////////////
//
// pushStateSetStack
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::pushStateSetStack(osg::StateSet* ss) {
_stack.push_back(osg::ref_ptr<osg::StateSet>(ss));
}
/////////////////////////////////////////////////////////////////////////
//
// popStateSetStack
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::popStateSetStack() {
if (!_stack.empty()) {
_stack.pop_back();
}
}
/////////////////////////////////////////////////////////////////////////
//
// getCurrentStateSet
//
/////////////////////////////////////////////////////////////////////////
osg::StateSet* ToVRML::getCurrentStateSet() {
// return current StateSet by flatten StateSet stack.
// until flatten is done, just return top StateSet
if (!_stack.empty()) {
osg::StateSet* ssFinal = new osg::StateSet();
ssFinal->setGlobalDefaults();
//std::cout << "StateSet Stack Size " << _stack.size() << std::endl;
for (unsigned int i = 0; i < _stack.size(); i++) {
osg::StateSet* ssCur = _stack[i].get();
if (ssCur != NULL) {
ssFinal->merge(*ssCur);
}
}
return (ssFinal);
} else
return (NULL);
}
/////////////////////////////////////////////////////////////////////////
//
// findMaterialName
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::findMaterialName(osg::Material* mat, std::string& name, bool& alreadyLoaded) {
osg::Vec4 ambient, diffuse, specular, emission;
//float shininess;
std::map<osg::ref_ptr<osg::Material>, std::string>::iterator it;// = _matMap.find(obj);
for (it = _matMap.begin(); it != _matMap.end(); it++) {
osg::ref_ptr < osg::Material > matLoaded = it->first;
ambient = mat->getAmbient(osg::Material::FRONT);
//diffuse = mat->getDiffuse(osg::Material::FRONT);
//specular = mat->getSpecular(osg::Material::FRONT);
//shininess = mat->getShininess(osg::Material::FRONT);
//emission = mat->getEmission(osg::Material::FRONT);
//std::cout << "MATERIAL " << ambient[3] << " " << matLoaded->getAmbient(osg::Material::FRONT)[3] << std::endl;
if ((matLoaded->getAmbient(osg::Material::FRONT) == mat->getAmbient(osg::Material::FRONT)) && (matLoaded->getDiffuse(osg::Material::FRONT)
== mat->getDiffuse(osg::Material::FRONT)) && (matLoaded->getSpecular(osg::Material::FRONT) == mat->getSpecular(osg::Material::FRONT))
&& (matLoaded->getShininess(osg::Material::FRONT) == mat->getShininess(osg::Material::FRONT)) && (matLoaded->getEmission(osg::Material::FRONT)
== mat->getEmission(osg::Material::FRONT))) {
name = it->second;
alreadyLoaded = true;
return;
}
}
std::stringstream ss;
ss << "material_" << _matMap.size();
name = ss.str();
_matMap[mat] = name;
alreadyLoaded = false;
}
/////////////////////////////////////////////////////////////////////////
//
// findTextureName
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::findTextureName(osg::Texture2D* tex, std::string& name, bool& alreadyLoaded) {
//std::cout << "ORI -" << tex->getImage() << "- " << std::endl;
if (tex->getImage() == NULL) {
tex->setImage(_defaultImage.get());
}
std::string nameOri = osgDB::convertFileNameToNativeStyle(tex->getImage()->getFileName());
std::string nameInput = osgDB::findDataFile(nameOri, NULL);
if (nameInput == "") {
osg::notify(osg::ALWAYS) << "WARNING: couldn't find texture named: -" << nameOri << "- use default one instead -" << _defaultImage->getFileName() << "-" << std::endl;
tex->setImage(_defaultImage.get());
nameOri = osgDB::convertFileNameToNativeStyle(tex->getImage()->getFileName());
nameInput = osgDB::findDataFile(nameOri, NULL);
}
std::string nameOutput;
std::string::size_type pos = nameInput.find_last_of(".");
std::string ext = nameInput.substr(pos, nameInput.length() - pos);
osg::ref_ptr < osg::Image > imgIn = osgDB::readImageFile(nameInput);
if (!imgIn.valid()) {
osg::notify(osg::ALWAYS) << "WARNING: couldn't read texture named: -" << nameOri << "- use default one instead -" << _defaultImage->getFileName() << "-" << std::endl;
tex->setImage(_defaultImage.get());
nameOri = osgDB::convertFileNameToNativeStyle(tex->getImage()->getFileName());
nameInput = osgDB::findDataFile(nameOri, NULL);
pos = nameInput.find_last_of(".");
nameInput.substr(pos, nameInput.length() - pos);
imgIn = _defaultImage.get();
}
//int nbBand = poSrcDS->GetRasterCount();
if (_textureMode == KEEP_ORIGINAL_TEXTURE) {
nameOutput = nameInput;
} else if (_textureMode == COPY_TEXTURE) {
nameOutput = _pathToOutput + "/" + _pathRelativeToOutput + "/" + osgDB::getSimpleFileName(nameInput);
} else if (_textureMode == CONVERT_TEXTURE) {
nameOutput = _pathToOutput + "/" + _pathRelativeToOutput + "/" + osgDB::getSimpleFileName(nameInput);
if (ext != ".png" && ext != ".jpg") {
if (imgIn->isImageTranslucent()) {//(nbBand != 1 && nbBand != 3) {
nameOutput = _pathToOutput + "/" + _pathRelativeToOutput + "/" + osgDB::getSimpleFileName(nameInput.substr(0, pos) + ".png");
} else {
nameOutput = _pathToOutput + "/" + _pathRelativeToOutput + "/" + osgDB::getSimpleFileName(nameInput.substr(0, pos) + ".jpg");
}
}
}
std::map<osg::ref_ptr<osg::Texture2D>, std::string>::iterator it;
for (it = _texMap.begin(); it != _texMap.end(); it++) {
osg::ref_ptr < osg::Texture2D > texLoaded = it->first;
if ((nameOutput == texLoaded->getImage()->getFileName()) && (tex->getWrap(osg::Texture::WRAP_S) == texLoaded->getWrap(osg::Texture::WRAP_S))
&& (tex->getWrap(osg::Texture::WRAP_T) == texLoaded->getWrap(osg::Texture::WRAP_T))) {
name = it->second;
alreadyLoaded = true;
return;
}
}
// first time we see these texture
// add it to textureMap
std::stringstream ss;
ss << "texture2D_" << _texMap.size();
name = ss.str();
_texMap[tex] = name;
alreadyLoaded = false;
tex->getImage()->setFileName(nameOutput);
if (nameInput == nameOutput) {
return;
}
// else write image file
if (_textureMode == CONVERT_TEXTURE) {
// convert format (from dds to rgb or rgba, or from rgba to rgb)
std::string newName;
GLenum type = GL_UNSIGNED_BYTE;
GLenum pixelFormat;
GLint internalFormat;
int nbC;
if (imgIn->isImageTranslucent()) {
// convert to png if transparency
pixelFormat = GL_RGBA;
internalFormat = GL_RGBA;
nbC = 4;
} else {
// convert to jpeg if no transparency
pixelFormat = GL_RGB;
internalFormat = GL_RGB;
nbC = 3;
}
osg::ref_ptr < osg::Image > curImg = tex->getImage();
osg::ref_ptr < osg::Image > mmImg = new osg::Image();
unsigned char* data = new unsigned char[curImg->s() * curImg->t() * nbC];
for (int j = 0; j < curImg->t(); j++) {
for (int i = 0; i < curImg->s(); i++) {
osg::Vec4 c = curImg->getColor(i, j);
data[(i + j * curImg->s()) * nbC] = c[0] * 255;
data[(i + j * curImg->s()) * nbC + 1] = c[1] * 255;
data[(i + j * curImg->s()) * nbC + 2] = c[2] * 255;
if (nbC == 4) {
data[(i + j * curImg->s()) * nbC + 3] = c[3] * 255;
}
}
}
mmImg->setImage(curImg->s(), curImg->t(), 1, internalFormat, pixelFormat, type, data, osg::Image::USE_NEW_DELETE, 1);
osgDB::writeImageFile(*(mmImg.get()), nameOutput);
} else {
// no conversion needed, input and output have the same format, but path to image has changed
osgDB::writeImageFile(*(tex->getImage()), nameOutput);
}
}
/////////////////////////////////////////////////////////////////////////
//
// writeCoordIndex
//
/////////////////////////////////////////////////////////////////////////
template<typename T> void ToVRML::writeCoordIndex(GLenum mode, T* indices, unsigned int number, std::vector<int>& primitiveSetFaces, int& primitiveFaces) {
int currentFaces = 0;
if (mode == osg::PrimitiveSet::TRIANGLES) {
//std::cout << "TRIANGLES" << std::endl;
for (unsigned int j = 0; j < number; j += 3) {
_fout << indent() << indices[j] << "," << indices[j + 1] << "," << indices[j + 2] << ",-1,\n";
currentFaces++;
}
primitiveSetFaces.push_back(currentFaces);
primitiveFaces += currentFaces;
} else if (mode == osg::PrimitiveSet::TRIANGLE_FAN) {
//std::cout << "TRIANGLE FAN" << std::endl;
int firstPoint = indices[0];
int secondPoint = indices[1];
for (unsigned int j = 2; j < number; j++) {
_fout << indent() << firstPoint << "," << secondPoint << "," << indices[j] << ",-1,\n";
secondPoint = indices[j];
currentFaces++;
}
primitiveSetFaces.push_back(currentFaces);
primitiveFaces += currentFaces;
} else if (mode == osg::PrimitiveSet::TRIANGLE_STRIP) {
//std::cout << "TRIANGLE STRIP" << std::endl;
int firstPoint = indices[0];
int secondPoint = indices[1];
bool changeSecond = false;
for (unsigned int j = 2; j < number; j++) {
_fout << indent() << firstPoint << "," << secondPoint << "," << indices[j] << ",-1,\n";
if (!changeSecond) {
firstPoint = indices[j];
changeSecond = true;
} else {
secondPoint = indices[j];
changeSecond = false;
}
currentFaces++;
}
primitiveSetFaces.push_back(currentFaces);
primitiveFaces += currentFaces;
} else if (mode == osg::PrimitiveSet::QUADS) {
//std::cout << "QUADS" << std::endl;
for (unsigned int j = 0; j < number; j += 4) {
_fout << indent() << indices[j] << "," << indices[j + 1] << "," << indices[j + 2] << "," << indices[j + 3] << ",-1,\n";
currentFaces++;
}
primitiveSetFaces.push_back(currentFaces);
primitiveFaces += currentFaces;
} else if (mode == osg::PrimitiveSet::QUAD_STRIP) {
//std::cout << "QUADS STRIP" << std::endl;
int firstPoint = indices[0];
int secondPoint = indices[1];
for (unsigned int j = 2; j < number; j += 2) {
_fout << indent() << firstPoint << "," << secondPoint << "," << indices[j + 1] << " " << indices[j] << ",-1,\n";
firstPoint = indices[j];
secondPoint = indices[j + 1];
currentFaces++;
}
primitiveSetFaces.push_back(currentFaces);
primitiveFaces += currentFaces;
} else if (mode == osg::PrimitiveSet::POLYGON) {
//std::cout << "POLYGON" << std::endl;
_fout << indent();
for (unsigned int j = 0; j < number; j++) {
_fout << indices[j] << ",";
}
currentFaces++;
_fout << "-1,\n";
primitiveSetFaces.push_back(currentFaces);
primitiveFaces += currentFaces;
} else {
osg::notify(osg::ALWAYS) << "Unknown Primitive Set Type : " << mode << std::endl;
}
}
/////////////////////////////////////////////////////////////////////////
//
// writeCoord
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::writeCoord(osg::Vec3Array* array) {
if (array == NULL) {
std::cerr << "Vec3Array is NULL" << std::endl;
return;
}
osg::ref_ptr < osg::Vec3Array > vArray = array;
_fout << indentM() << "coord Coordinate {\n";
_fout << indentM() << "point [\n";
indentM();
osg::Vec3 xyz;
for (unsigned int j = 0; j < vArray->size(); j++) {
xyz = (*vArray)[j];
_fout << indent() << xyz[0] << " " << xyz[1] << " " << xyz[2] << ",\n";
}
_fout << indentL() << "]\n";
_fout << indentL() << "}\n";
indentL();
}
/////////////////////////////////////////////////////////////////////////
//
// writeTexCoord
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::writeTexCoord(osg::Vec2Array* array, osg::Vec3Array* array2) {
osg::ref_ptr < osg::StateSet > ss = getCurrentStateSet();
osg::Texture2D* tex = (osg::Texture2D*) (ss->getTextureAttribute(_txtUnit, osg::StateAttribute::TEXTURE));
if (tex == NULL) {
return;
}
osg::ref_ptr < osg::TexGen > texGen = dynamic_cast<osg::TexGen*> (ss->getTextureAttribute(_txtUnit, osg::StateAttribute::TEXGEN));
osg::ref_ptr < osg::TexEnv > texEnv = dynamic_cast<osg::TexEnv*> (ss->getTextureAttribute(_txtUnit, osg::StateAttribute::TEXENV));
osg::Texture::WrapMode wrap_s = tex->getWrap(osg::Texture::WRAP_S);//osg::Texture::REPEAT;
osg::Texture::WrapMode wrap_t = tex->getWrap(osg::Texture::WRAP_T);//osg::Texture::REPEAT;
if (array != NULL) {
writeUVArray(array, wrap_s, wrap_t);
} else if (texGen.valid()) {
//std::cout << "TEXGEN" << std::endl;
osg::ref_ptr < osg::Vec2Array > uvArray = buildUVArray(texGen.get(), array2);
if (uvArray.valid()) {
writeUVArray(uvArray.get(), wrap_s, wrap_t);
}
} else if (texEnv.valid()) {
//std::cout << "TEXENV" << std::endl;
osg::ref_ptr < osg::Vec2Array > uvArray = buildUVArray(texEnv.get(), array2);
if (uvArray.valid()) {
writeUVArray(uvArray.get(), wrap_s, wrap_t);
}
}
}
/////////////////////////////////////////////////////////////////////////
//
// writeNormal
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::writeNormal(osg::Geometry* geom, std::vector<int>& primitiveSetFaces, int nbFaces) {
osg::ref_ptr < osg::Vec3Array > nArray = (osg::Vec3Array*) (geom->getNormalArray());
if (!nArray.valid()) {
return;
}
if (geom->getNormalBinding() == osg::Geometry::BIND_PER_VERTEX || geom->getNormalBinding() == osg::Geometry::BIND_OVERALL) {
_fout << indentM() << "normalPerVertex TRUE \n";
} else {
_fout << indentM() << "normalPerVertex FALSE \n";
}
_fout << indent() << "normal Normal {\n";
_fout << indentM() << "vector [\n";
indentM();
osg::Vec3 n;
if (geom->getNormalBinding() == osg::Geometry::BIND_PER_VERTEX) {
for (unsigned int j = 0; j < (*nArray).size(); j++) {
n = (*nArray)[j];
_fout << indent() << n[0] << " " << n[1] << " " << n[2] << ",\n";
}
} else if (geom->getNormalBinding() == osg::Geometry::BIND_OVERALL) {
n = (*nArray)[0];
int size = ((osg::Vec3Array*) (geom->getVertexArray()))->size();
for (int j = 0; j < size; j++) {
_fout << indent() << n[0] << " " << n[1] << " " << n[2] << ",\n";
}
} else if (geom->getNormalBinding() == osg::Geometry::BIND_PER_PRIMITIVE) {
for (unsigned int j = 0; j < (*nArray).size(); j++) {
n = (*nArray)[j];
_fout << indent() << n[0] << " " << n[1] << " " << n[2] << ",\n";
}
} else if (geom->getNormalBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) {
for (unsigned int j = 0; j < (*nArray).size(); j++) {
n = (*nArray)[j];
for (int k = 0; k < primitiveSetFaces[j]; k++) {
_fout << indent() << n[0] << " " << n[1] << " " << n[2] << ",\n";
}
}
}
_fout << indentL() << "]\n";
_fout << indentL() << "}\n";
indentL();
}
/////////////////////////////////////////////////////////////////////////
//
// writeUVArray
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::writeUVArray(osg::Vec2Array* uvArray, osg::Texture::WrapMode wrap_s, osg::Texture::WrapMode wrap_t) {
_fout << indentM() << "texCoord TextureCoordinate {\n";
_fout << indentM() << "point [\n";
indentM();
osg::Vec2 uv;
for (unsigned int j = 0; j < (*uvArray).size(); j++) {
uv = (*uvArray)[j];
if (wrap_s != osg::Texture::REPEAT) {
// clamp to 0-1
if (uv[0] < 0) {
uv[0] = 0;
} else if (uv[0] > 1) {
uv[0] = 1;
}
}
if (wrap_t != osg::Texture::REPEAT) {
// clamp to 0-1
if (uv[1] < 0) {
uv[1] = 0;
} else if (uv[1] > 1) {
uv[1] = 1;
}
}
_fout << indent() << uv[0] << " " << uv[1] << ",\n";
}
_fout << indentL() << "]\n";
_fout << indentL() << "}\n";
indentL();
}
/////////////////////////////////////////////////////////////////////////
//
// buildUVArray
//
/////////////////////////////////////////////////////////////////////////
osg::Vec2Array* ToVRML::buildUVArray(osg::TexGen* tGen, osg::Vec3Array* array) {
osg::ref_ptr < osg::TexGen > texGen = tGen;
osg::ref_ptr < osg::Vec3Array > vArray = array;
osg::Vec2Array* uvRet = NULL;
osg::TexGen::Mode mode = texGen->getMode();
if (mode == osg::TexGen::OBJECT_LINEAR) {
//std::cout << "I know" << std::endl;
uvRet = new osg::Vec2Array();
osg::Plane planS = texGen->getPlane(osg::TexGen::S);//, osg::Vec4(1 / rangeS, 0, 0, -(adfGeoTransform[0] / rangeS)));
osg::Plane planT = texGen->getPlane(osg::TexGen::T);//, osg::Vec4(0, 1 / rangeT, 0, -(adfGeoTransform[3] + sy * adfGeoTransform[5]) / rangeT));
osg::Vec4 pS = planS.asVec4();
osg::Vec4 pT = planT.asVec4();
double width, height, xmin, ymin;
width = 1.0 / pS[0];
height = 1.0 / pT[1];
xmin = -width * pS[3];
ymin = -height * pT[3];
for (unsigned int j = 0; j < vArray->size(); j++) {
osg::Vec3d p = (*vArray)[j];
double x, y;
osg::Vec2 uv;
x = p[0];
y = p[1];
uv[0] = (x - xmin) / width;
uv[1] = (y - ymin) / height;
(*uvRet).push_back(uv);
}
} else {
osg::notify(osg::ALWAYS) << "Unknown TexGen mode" << std::endl;
}
return (uvRet);
}
/////////////////////////////////////////////////////////////////////////
//
// buildUVArray
//
/////////////////////////////////////////////////////////////////////////
osg::Vec2Array* ToVRML::buildUVArray(osg::TexEnv* tEnv, osg::Vec3Array* array) {
osg::ref_ptr < osg::TexEnv > texEnv = tEnv;
osg::Vec2Array* uvRet = NULL;
// osg::TexEnv::Mode mode = texEnv->getMode();
//if (mode == osg::TexEnv::MODULATE) {
// std::cout << "I know" << std::endl;
//} else {
osg::notify(osg::ALWAYS) << "Unknown TexEnv mode" << std::endl;
//}
return (uvRet);
}
/////////////////////////////////////////////////////////////////////////
//
// writeColor
//
/////////////////////////////////////////////////////////////////////////
void ToVRML::writeColor(osg::Geometry* geom, std::vector<int>& primitiveSetFaces, int nbFaces) {
osg::ref_ptr < osg::Vec4Array > cArray = (osg::Vec4Array*) (geom->getColorArray());
if (!cArray.valid()) {
return;
}
if (geom->getColorBinding() == osg::Geometry::BIND_PER_VERTEX || geom->getColorBinding() == osg::Geometry::BIND_OVERALL) {
_fout << indentM() << "colorPerVertex TRUE \n";
} else {
_fout << indentM() << "colorPerVertex FALSE \n";
}
_fout << indent() << "color Color {\n";
_fout << indentM() << "color [\n";
indentM();
osg::Vec4 c;
if (geom->getColorBinding() == osg::Geometry::BIND_PER_VERTEX) {
for (unsigned int j = 0; j < (*cArray).size(); j++) {
c = (*cArray)[j];
_fout << indent() << c[0] << " " << c[1] << " " << c[2] << ",\n";
}
} else if (geom->getColorBinding() == osg::Geometry::BIND_OVERALL) {
c = (*cArray)[0];
int size = ((osg::Vec3Array*) (geom->getVertexArray()))->size();
for (int j = 0; j < size; j++) {
_fout << indent() << c[0] << " " << c[1] << " " << c[2] << ",\n";
}
} else if (geom->getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE) {
for (unsigned int j = 0; j < (*cArray).size(); j++) {
c = (*cArray)[j];
_fout << indent() << c[0] << " " << c[1] << " " << c[2] << ",\n";
}
} else if (geom->getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) {
for (unsigned int j = 0; j < (*cArray).size(); j++) {
c = (*cArray)[j];
for (int k = 0; k < primitiveSetFaces[j]; k++) {
_fout << indent() << c[0] << " " << c[1] << " " << c[2] << ",\n";
}
}
}
_fout << indentL() << "]\n";
_fout << indentL() << "}\n";
indentL();
}