diff --git a/Make/makedirdefs b/Make/makedirdefs index 4671e3ed5..dad57e940 100644 --- a/Make/makedirdefs +++ b/Make/makedirdefs @@ -31,7 +31,6 @@ PLUGIN_DIRS = \ dds\ dw\ flt\ - iv\ lib3ds\ logo\ lwo\ @@ -61,6 +60,18 @@ PLUGIN_DIRS = \ # comment in if have freetype2.x installed, provides type type font support to osgText. PLUGIN_DIRS += freetype +# comment in of your have Inventor or coin installed +ifneq ("$(USE_COIN)","") + PLUGIN_DIRS += Inventor +else + ifneq ("$(USE_INVENTOR)","") + PLUGIN_DIRS += Inventor + else + PLUGIN_DIRS += iv + endif +endif + + # Geo plugin breaks Darwin build and doens't handle BigEndian issue. ifneq ($(OS),Darwin) @@ -158,7 +169,6 @@ EXAMPLE_DIRS = \ osgwindows\ # osgpagedlod\ -# osgsimulation\ # osgdemeter\ # osgjigsaw\ diff --git a/src/osgPlugins/Inventor/ConvertFromInventor.cpp b/src/osgPlugins/Inventor/ConvertFromInventor.cpp new file mode 100644 index 000000000..d4cec0aa8 --- /dev/null +++ b/src/osgPlugins/Inventor/ConvertFromInventor.cpp @@ -0,0 +1,929 @@ +#include "ConvertFromInventor.h" +#include "PendulumCallback.h" +#include "ShuttleCallback.h" + +// OSG headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Inventor headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GroupSoLOD.h" + +#include +#include +#ifdef __linux +#include +#endif +#ifdef __APPLE__ +#include +#endif + +ConvertFromInventor::ConvertFromInventor() +{ + numPrimitives = 0; +} + +ConvertFromInventor::~ConvertFromInventor() +{ +} + +osg::Node* ConvertFromInventor::convert(SoNode* rootIVNode) +{ + // Transformation matrix for converting Inventor coordinate system to OSG + // coordinate system + osg::Matrix ivToOSGMat(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)); + + // Create a root node and push it onto the stack + osg::MatrixTransform* root = new osg::MatrixTransform; + root->setMatrix(ivToOSGMat); + groupStack.push(root); + + // Push an empty list of light and push it onto the light stack + LightList lightList; + lightStack.push(lightList); + + // Create callback actions for the inventor nodes + // These callback functions perform the conversion + SoCallbackAction cbAction; + cbAction.addPreCallback(SoShape::getClassTypeId(), preShape, this); + cbAction.addPostCallback(SoShape::getClassTypeId(), postShape, this); + cbAction.addPreCallback(SoGroup::getClassTypeId(), preGroup, this); + cbAction.addPostCallback(SoGroup::getClassTypeId(), postGroup, this); + cbAction.addPreCallback(SoTexture2::getClassTypeId(), preTexture, this); + cbAction.addPreCallback(SoLight::getClassTypeId(), preLight, this); + cbAction.addPreCallback(SoRotor::getClassTypeId(), preRotor, this); + cbAction.addPreCallback(SoPendulum::getClassTypeId(), prePendulum, this); + cbAction.addPreCallback(SoShuttle::getClassTypeId(), preShuttle, this); + cbAction.addTriangleCallback(SoShape::getClassTypeId(), addTriangleCB, this); + cbAction.addLineSegmentCallback(SoShape::getClassTypeId(), addLineSegmentCB, + this); + cbAction.addPointCallback(SoShape::getClassTypeId(), addPointCB, this); + + // Traverse the inventor scene graph + cbAction.apply(rootIVNode); + + // Pop the root osg node + groupStack.pop(); + + lightStack.pop(); + + return root; +} + +SoCallbackAction::Response +ConvertFromInventor::preShape(void* data, SoCallbackAction* action, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preShape() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Normal and color binding map from Inventor to OSG + static std::map + normBindingMap; + static std::map + colBindingMap; + static bool firstTime = true; + if (firstTime) + { + normBindingMap[SoNormalBinding::OVERALL] + = osg::Geometry::BIND_OVERALL; + normBindingMap[SoNormalBinding::PER_PART] + = osg::Geometry::BIND_PER_PRIMITIVE; + normBindingMap[SoNormalBinding::PER_PART_INDEXED] + = osg::Geometry::BIND_PER_PRIMITIVE; + normBindingMap[SoNormalBinding::PER_FACE] + = osg::Geometry::BIND_PER_PRIMITIVE; + normBindingMap[SoNormalBinding::PER_FACE_INDEXED] + = osg::Geometry::BIND_PER_PRIMITIVE; + normBindingMap[SoNormalBinding::PER_VERTEX] + = osg::Geometry::BIND_PER_VERTEX; + normBindingMap[SoNormalBinding::PER_VERTEX_INDEXED] + = osg::Geometry::BIND_PER_VERTEX; + + colBindingMap[SoMaterialBinding::OVERALL] + = osg::Geometry::BIND_OVERALL; + colBindingMap[SoMaterialBinding::PER_PART] + = osg::Geometry::BIND_PER_PRIMITIVE; + colBindingMap[SoMaterialBinding::PER_PART_INDEXED] + = osg::Geometry::BIND_PER_PRIMITIVE; + colBindingMap[SoMaterialBinding::PER_FACE] + = osg::Geometry::BIND_PER_PRIMITIVE; + colBindingMap[SoMaterialBinding::PER_FACE_INDEXED] + = osg::Geometry::BIND_PER_PRIMITIVE; + colBindingMap[SoMaterialBinding::PER_VERTEX] + = osg::Geometry::BIND_PER_VERTEX; + colBindingMap[SoMaterialBinding::PER_VERTEX_INDEXED] + = osg::Geometry::BIND_PER_VERTEX; + + firstTime = false; + } + + // Get normal and color binding + if (node->isOfType(SoVertexShape::getClassTypeId())) + { + thisPtr->normalBinding = normBindingMap[action->getNormalBinding()]; + thisPtr->colorBinding = colBindingMap[action->getMaterialBinding()]; + } + else + { + thisPtr->normalBinding = osg::Geometry::BIND_PER_VERTEX; + thisPtr->colorBinding = osg::Geometry::BIND_PER_VERTEX; + } + + // Check vertex ordering + if (action->getVertexOrdering() == SoShapeHints::CLOCKWISE) + thisPtr->vertexOrder = CLOCKWISE; + else + thisPtr->vertexOrder = COUNTER_CLOCKWISE; + + // Clear the data from the previous shape callback + thisPtr->numPrimitives = 0; + thisPtr->vertices.clear(); + thisPtr->normals.clear(); + thisPtr->colors.clear(); + thisPtr->textureCoords.clear(); + + return SoCallbackAction::CONTINUE; +} + +// OSG doesn't seem to have a transpose function for matrices +void ConvertFromInventor::transposeMatrix(osg::Matrix& mat) +{ + float tmp; + for (int j = 0; j < 4; j++) + { + for (int i = j + 1; i < 4; i++) + { + tmp = mat.operator()(j,i); + mat.operator()(j,i) = mat.operator()(i,j); + mat.operator()(i,j) = tmp; + } + } + +} + +SoCallbackAction::Response +ConvertFromInventor::postShape(void* data, SoCallbackAction* action, + const SoNode* ) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "postShape() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Get the modeling matrix + osg::Matrix modelMat; + modelMat.set((float *)action->getModelMatrix().getValue()); + + // Tranform the vertices based on the modeling matrix + osg::Vec3Array* coords = new osg::Vec3Array(thisPtr->vertices.size()); + for (unsigned int i = 0; i < thisPtr->vertices.size(); i++) + (*coords)[i] = modelMat.preMult(thisPtr->vertices[i]); + + // Normals need to be transformed using the transpose of the inverse + // modeling matrix + osg::Matrix invModelMat; + invModelMat.invert(modelMat); + thisPtr->transposeMatrix(invModelMat); + + // Tranform the normals based on the modeling matrix + osg::Vec3Array* norms = NULL; + if (thisPtr->normalBinding == osg::Geometry::BIND_OVERALL) + { + norms = new osg::Vec3Array(1); + const SbVec3f &norm = action->getNormal(0); + (*norms)[0].set(norm[0], norm[1], norm[2]); + (*norms)[0] = invModelMat.transform3x3((*norms)[0],invModelMat); + (*norms)[0].normalize(); + } + else + { + norms = new osg::Vec3Array(thisPtr->normals.size()); + for (unsigned int i = 0; i < thisPtr->normals.size(); i++) + { + (*norms)[i] = invModelMat.transform3x3(thisPtr->normals[i], + invModelMat); + (*norms)[i].normalize(); + } + } + + // Set the colors + osg::Vec4Array* cols; + if (thisPtr->colorBinding == osg::Geometry::BIND_OVERALL) + { + cols = new osg::Vec4Array(1); + SbColor ambient, diffuse, specular, emission; + float transparency, shininess; + action->getMaterial(ambient, diffuse, specular, emission, shininess, + transparency, 0); + (*cols)[0].set(diffuse[0], diffuse[1], diffuse[2], 1.0 - transparency); + } + else + { + cols = new osg::Vec4Array(thisPtr->colors.size()); + for (unsigned int i = 0; i < thisPtr->colors.size(); i++) + (*cols)[i] = thisPtr->colors[i]; + } + + + // Get the texture transformation matrix + osg::Matrix textureMat; + textureMat.set((float *) action->getTextureMatrix().getValue()); + + // Transform texture coordinates if texture matrix is not an identity mat + osg::Matrix identityMat; + identityMat.makeIdentity(); + osg::Vec2Array* texCoords + = new osg::Vec2Array(thisPtr->textureCoords.size()); + if (textureMat == identityMat) + { + // Set the texture coordinates + for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++) + (*texCoords)[i] = thisPtr->textureCoords[i]; + } + else + { + // Transform and set the texture coordinates + for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++) + { + osg::Vec3 transVec = textureMat.preMult( + osg::Vec3(thisPtr->textureCoords[i][0], + thisPtr->textureCoords[i][1], + 0.0)); + (*texCoords)[i].set(transVec.x(), transVec.y()); + } + } + + + // Create a new Geometry + osg::Geometry* geometry = new osg::Geometry; + + // Set the parameters for the geometry + geometry->setVertexArray(coords); + geometry->setColorArray(cols); + geometry->setColorBinding(thisPtr->colorBinding); + geometry->setNormalArray(norms); + geometry->setNormalBinding(thisPtr->normalBinding); + geometry->setTexCoordArray(0, texCoords); + + geometry->addPrimitiveSet(new osg::DrawArrays(thisPtr->primitiveType,0, + coords->size())); + + // Get the StateSet for the geoset + osg::StateSet* stateSet = thisPtr->getStateSet(action); + geometry->setStateSet(stateSet); + + // Add the geoset to a geode + osg::Geode* geode = new osg::Geode; + geode->addDrawable(geometry); + + // Add geode to scenegraph + thisPtr->groupStack.top()->addChild(geode); + + return SoCallbackAction::CONTINUE; +} + +SoCallbackAction::Response +ConvertFromInventor::preTexture(void* data, SoCallbackAction *, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preTexture() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + if (thisPtr->soTexStack.size()) + thisPtr->soTexStack.pop() ; + thisPtr->soTexStack.push((SoTexture2 *)node) ; + + return SoCallbackAction::CONTINUE; +} + +void ConvertFromInventor::transformLight(SoCallbackAction* action, + const SbVec3f& vec, + osg::Vec3& transVec) +{ + osg::Matrix modelMat; + modelMat.set((float *)action->getModelMatrix().getValue()); + + transVec.set(vec[0], vec[1], vec[2]); + transVec = modelMat.preMult(transVec); +} + +SoCallbackAction::Response +ConvertFromInventor::preLight(void* data, SoCallbackAction* action, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preLight() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + static int lightNum = 1; + + // Return if the light is not on + const SoLight* ivLight = (const SoLight*) node; + if (!ivLight->on.getValue()) + return SoCallbackAction::CONTINUE; + + osg::Light* osgLight = new osg::Light; + osgLight->setLightNum(lightNum++); + + // Get color and intensity + SbVec3f lightColor = ivLight->color.getValue(); + float intensity = ivLight->intensity.getValue(); + + // Set color and intensity + osgLight->setDiffuse(osg::Vec4(lightColor[0] * intensity, + lightColor[1] * intensity, + lightColor[2] * intensity, 1)); + + if (node->isOfType(SoDirectionalLight::getClassTypeId())) + { + SoDirectionalLight *dirLight = (SoDirectionalLight *) node; + + osg::Vec3 transVec; + thisPtr->transformLight(action, dirLight->direction.getValue(), transVec); + osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(), + transVec.z(), 0)); + } + else if (node->isOfType(SoPointLight::getClassTypeId())) + { + SoPointLight* ptLight = (SoPointLight *) node; + + osg::Vec3 transVec; + thisPtr->transformLight(action, ptLight->location.getValue(), transVec); + osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(), + transVec.z(), 0)); + } + else if (node->isOfType(SoSpotLight::getClassTypeId())) + { + SoSpotLight* spotLight = (SoSpotLight *) node; + + osgLight->setSpotExponent(spotLight->dropOffRate.getValue() * 128.0); + osgLight->setSpotCutoff(spotLight->cutOffAngle.getValue()*180.0/M_PI); + + osg::Vec3 transVec; + thisPtr->transformLight(action, spotLight->location.getValue(), transVec); + osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(), + transVec.z(), 0)); + + thisPtr->transformLight(action, spotLight->direction.getValue(),transVec); + osgLight->setDirection(osg::Vec3(transVec.x(), transVec.y(), + transVec.z())); + } + + // Add light to list in the current level + if (thisPtr->lightStack.size()) + { + LightList lightList; + lightList = thisPtr->lightStack.top(); + lightList.push_back(osgLight); + thisPtr->lightStack.pop(); + thisPtr->lightStack.push(lightList); + } + + return SoCallbackAction::CONTINUE; +} + +osg::StateSet* ConvertFromInventor::getStateSet(SoCallbackAction* action) +{ + osg::StateSet* stateSet = new osg::StateSet; + + // Inherit modes from the global state + stateSet->setAllToInherit(); + + SbColor ambient, diffuse, specular, emission; + float shininess, transparency; + + // Get the material colors + action->getMaterial(ambient, diffuse, specular, emission, + shininess, transparency, 0); + + // Set transparency + if (transparency > 0) + { + osg::BlendFunc* transparency = new osg::BlendFunc; + stateSet->setAttributeAndModes(transparency, + osg::StateAttribute::ON); + + // Enable depth sorting for transparent objects + stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + } + + // Set linewidth + if (action->getLineWidth()) + { + osg::LineWidth* lineWidth = new osg::LineWidth; + lineWidth->setWidth(action->getLineWidth()); + stateSet->setAttributeAndModes(lineWidth, osg::StateAttribute::ON); + } + + // Set pointsize + if (action->getPointSize()) + { + osg::Point* point = new osg::Point; + point->setSize(action->getPointSize()); + stateSet->setAttributeAndModes(point, osg::StateAttribute::ON); + } + + // Set draw mode + osg::PolygonMode *polygonMode = new osg::PolygonMode; + switch (action->getDrawStyle()) + { + case SoDrawStyle::FILLED: + polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, + osg::PolygonMode::FILL); + break; + case SoDrawStyle::LINES: + polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, + osg::PolygonMode::LINE); + break; + case SoDrawStyle::POINTS: + polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, + osg::PolygonMode::POINT); + break; + case SoDrawStyle::INVISIBLE: + // check how to handle this in osg. + break; + } + stateSet->setAttributeAndModes(polygonMode, osg::StateAttribute::ON); + + // Set back face culling + if (action->getShapeType() == SoShapeHints::SOLID) + { + osg::CullFace* cullFace = new osg::CullFace; + cullFace->setMode(osg::CullFace::BACK); + stateSet->setAttributeAndModes(cullFace, osg::StateAttribute::ON); + } + + // Set lighting + if (action->getLightModel() == SoLightModel::BASE_COLOR) + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + else + { + // Set the material + osg::Material* material = new osg::Material; + + material->setAmbient(osg::Material::FRONT_AND_BACK, + osg::Vec4(ambient[0], ambient[1], ambient[2], + 1.0 - transparency)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, + osg::Vec4(diffuse[0], diffuse[1], diffuse[2], + 1.0 - transparency)); + material->setSpecular(osg::Material::FRONT_AND_BACK, + osg::Vec4(specular[0], specular[1], specular[2], + 1.0 - transparency)); + material->setEmission(osg::Material::FRONT_AND_BACK, + osg::Vec4(emission[0], emission[1], emission[2], + 1.0 - transparency)); + material->setTransparency(osg::Material::FRONT_AND_BACK, transparency); + if (specular[0] || specular[1] || specular[2]) + material->setShininess(osg::Material::FRONT_AND_BACK, + shininess*128.0); + else + material->setShininess(osg::Material::FRONT_AND_BACK, 0.0); + + material->setColorMode(osg::Material::DIFFUSE); + + stateSet->setAttributeAndModes(material, osg::StateAttribute::ON); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON); + + // Set two sided lighting + osg::LightModel* lightModel = new osg::LightModel; + lightModel->setTwoSided(true); + stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON); + + // Set lights + LightList lightList = lightStack.top(); + for (unsigned int i = 0; i < lightList.size(); i++) + stateSet->setAttributeAndModes(lightList[i], + osg::StateAttribute::ON); + } + + // Convert the IV texture to OSG texture if any + if (soTexStack.top()) + { + osg::Texture2D* tex; + // Found a corresponding OSG texture object + if (ivToOsgTexMap[soTexStack.top()]) + tex = ivToOsgTexMap[soTexStack.top()]; + else + { + // Create a new osg texture + tex = convertIVTexToOSGTex(soTexStack.top(), action); + + // Add the new texture to the database + ivToOsgTexMap[soTexStack.top()] = tex; + } + + stateSet->setTextureAttributeAndModes(0,tex, osg::StateAttribute::ON); + + // Set the texture environment + osg::TexEnv* texEnv = new osg::TexEnv; + switch (action->getTextureModel()) + { + case SoTexture2::MODULATE: + texEnv->setMode(osg::TexEnv::MODULATE); + break; + case SoTexture2::DECAL: + texEnv->setMode(osg::TexEnv::DECAL); + break; + case SoTexture2::BLEND: + texEnv->setMode(osg::TexEnv::BLEND); + break; + } + stateSet->setTextureAttributeAndModes(0,texEnv,osg::StateAttribute::ON); + } + + return stateSet; +} + +osg::Texture2D* +ConvertFromInventor::convertIVTexToOSGTex(SoTexture2* soTex, + SoCallbackAction* action) +{ + SbVec2s soTexSize; + int soTexNC; + + // Get the texture size and components + const unsigned char* texImage; + texImage = soTex->image.getValue(soTexSize, soTexNC); + if (!texImage) + return NULL; + + // Allocate memory for image data + unsigned char* imageData = new unsigned char[soTexSize[0] * soTexSize[1] * + soTexNC]; + + // Copy the texture image data from the inventor texture + memcpy(imageData, texImage, soTexSize[0] * soTexSize[1] * soTexNC); + + // Create the osg image + osg::Image* osgTexImage = new osg::Image; + GLenum formats[] = {GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA}; + osgTexImage->setImage(soTexSize[0], soTexSize[1], 0, soTexNC, + formats[soTexNC-1], GL_UNSIGNED_BYTE, imageData, + osg::Image::USE_NEW_DELETE, -1); + + // Create the osg texture + osg::Texture2D* osgTex = new osg::Texture2D; + osgTex->setImage(osgTexImage); + + static std::map texWrapMap; + static bool firstTime = true; + if (firstTime) + { + texWrapMap[SoTexture2::CLAMP] = osg::Texture2D::CLAMP; + texWrapMap[SoTexture2::REPEAT] = osg::Texture2D::REPEAT; + firstTime = false; + } + + // Set texture wrap mode + osgTex->setWrap(osg::Texture2D::WRAP_S,texWrapMap[action->getTextureWrapS()]); + osgTex->setWrap(osg::Texture2D::WRAP_T,texWrapMap[action->getTextureWrapT()]); + + return osgTex; +} + +SoCallbackAction::Response +ConvertFromInventor::preGroup(void* data, SoCallbackAction* action, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preGroup() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Handle SoLOD nodes + if (node->getTypeId() == GroupSoLOD::getClassTypeId()) + return preLOD(data, action, node); + + // Create a new group and add it to the stack + osg::Group* group = new osg::Group; + thisPtr->groupStack.push(group); + + if (node->isOfType(SoSeparator::getClassTypeId())) + { + if (thisPtr->soTexStack.size()) + thisPtr->soTexStack.push(thisPtr->soTexStack.top()); + else + thisPtr->soTexStack.push(NULL); + if (thisPtr->lightStack.size()) + { + LightList lightList = thisPtr->lightStack.top(); + thisPtr->lightStack.push(lightList); + } + } + + return SoCallbackAction::CONTINUE; +} + +SoCallbackAction::Response +ConvertFromInventor::postGroup(void* data, SoCallbackAction *, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "postGroup() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Pop all the groups that are Transforms and add it + // to the corresponding parent group + osg::Group* group = thisPtr->groupStack.top(); + while (strcmp(group->className(), "MatrixTransform") == 0) + { + thisPtr->groupStack.pop(); + thisPtr->groupStack.top()->addChild(group); + group = thisPtr->groupStack.top(); + } + + // Pop the group from the stack and add it to it's parent + thisPtr->groupStack.pop(); + thisPtr->groupStack.top()->addChild(group); + + // Pop the state if the group is a Separator + if (node->isOfType(SoSeparator::getClassTypeId())) + { + thisPtr->soTexStack.pop(); + thisPtr->lightStack.pop(); + } + + return SoCallbackAction::CONTINUE; +} + +SoCallbackAction::Response +ConvertFromInventor::preLOD(void* data, SoCallbackAction *, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preLOD() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Inventor LOD node + SoLOD *ivLOD = (SoLOD *) node; + + // Create a new LOD and add it to the stack + osg::LOD* lod = new osg::LOD; + thisPtr->groupStack.push(lod); + + // Get the center of LOD and set it + SbVec3f ivCenter = ivLOD->center.getValue(); + lod->setCenter(osg::Vec3(ivCenter[0], ivCenter[1], ivCenter[2])); + + // Get the ranges and set it + // lod->setRange(0, 0.0); + lod->setRange(0, 0.0, ivLOD->range[0]); + for (int i = 1; i < ivLOD->getChildren()->getLength(); i++) + lod->setRange(i, ivLOD->range[i-1], ivLOD->range[i]); + + lod->setRange(ivLOD->getChildren()->getLength(), + ivLOD->range[ivLOD->getChildren()->getLength()],FLT_MAX); + + return SoCallbackAction::CONTINUE; +} + +SoCallbackAction::Response +ConvertFromInventor::preRotor(void* data, SoCallbackAction *, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preRotor() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Get the parameters for the inventor Rotor + SoRotor *ivRotor = (SoRotor *) node; + SbVec3f ivAxis; + float angle; + ivRotor->rotation.getValue(ivAxis, angle); + + // Create a new osg::MatrixTransform + osg::MatrixTransform* rotorTransform = new osg::MatrixTransform; + + // Create a Rotor Callback equivalent to the inventor Rotor + osg::Vec3 pivot(0, 0, 0); + osg::Vec3 axis(ivAxis[0], ivAxis[1], ivAxis[2]); + osgUtil::TransformCallback* rotorCallback + = new osgUtil::TransformCallback(pivot, axis, + 2 * M_PI * ivRotor->speed.getValue()); + + // Set the app callback + rotorTransform->setUpdateCallback(rotorCallback); + + // Push the rotor transform onto the group stack + thisPtr->groupStack.push(rotorTransform); + + return SoCallbackAction::CONTINUE; +} + +SoCallbackAction::Response +ConvertFromInventor::prePendulum(void* data, SoCallbackAction *, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "prePendulum() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Get the parameters for the inventor Pendulum + SoPendulum *ivPendulum = (SoPendulum *) node; + SbVec3f ivAxis0, ivAxis1; + float startAngle, endAngle; + ivPendulum->rotation0.getValue(ivAxis0, startAngle); + ivPendulum->rotation1.getValue(ivAxis1, endAngle); + + // Create a new osg::MatrixTransform + osg::MatrixTransform* pendulumTransform = new osg::MatrixTransform; + + // Create a Pendulum Callback equivalent to the inventor Rotor + osg::Vec3 axis(ivAxis0[0], ivAxis0[1], ivAxis0[2]); + PendulumCallback* pendulumCallback + = new PendulumCallback(axis, startAngle, endAngle, + ivPendulum->speed.getValue()); + + // Set the app callback + pendulumTransform->setUpdateCallback(pendulumCallback); + + // Push the pendulum transform onto the group stack + thisPtr->groupStack.push(pendulumTransform); + + return SoCallbackAction::CONTINUE; +} + +SoCallbackAction::Response +ConvertFromInventor::preShuttle(void* data, SoCallbackAction *, + const SoNode* node) +{ +#ifdef DEBUG_IV_PLUGIN + std::cout << "preShuttle() " + << node->getTypeId().getName().getString() << std::endl; +#endif + + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + // Get the parameters for the inventor Shuttle + SoShuttle *ivShuttle = (SoShuttle *) node; + SbVec3f ivStartPos, ivEndPos; + ivStartPos = ivShuttle->translation0.getValue(); + ivEndPos = ivShuttle->translation1.getValue(); + + // Create a new osg::MatrixTransform + osg::MatrixTransform* shuttleTransform = new osg::MatrixTransform; + + // Create a shuttle Callback equivalent to the inventor Rotor + osg::Vec3 startPos(ivStartPos[0], ivStartPos[1], ivStartPos[2]); + osg::Vec3 endPos(ivEndPos[0], ivEndPos[1], ivEndPos[2]); + ShuttleCallback* shuttleCallback + = new ShuttleCallback(startPos, endPos, ivShuttle->speed.getValue()); + + // Set the app callback + shuttleTransform->setUpdateCallback(shuttleCallback); + + // Push the shuttle transform onto the group stack + thisPtr->groupStack.push(shuttleTransform); + + return SoCallbackAction::CONTINUE; +} + + +void ConvertFromInventor::addVertex(SoCallbackAction* action, + const SoPrimitiveVertex *v, int index) +{ + // Get the coordinates of the vertex + SbVec3f pt = v->getPoint(); + vertices.push_back(osg::Vec3(pt[0], pt[1], pt[2])); + + // Get the normal of the vertex + SbVec3f norm = v->getNormal(); + + if ((normalBinding == osg::Geometry::BIND_PER_VERTEX) || + (normalBinding == osg::Geometry::BIND_PER_PRIMITIVE && index == 0)) + { + if (vertexOrder == CLOCKWISE) + normals.push_back(osg::Vec3(-norm[0], -norm[1], -norm[2])); + else + normals.push_back(osg::Vec3(norm[0], norm[1], norm[2])); + } + + if (colorBinding == osg::Geometry::BIND_PER_VERTEX || + colorBinding == osg::Geometry::BIND_PER_PRIMITIVE) + { + // Get the material/color + SbColor ambient, diffuse, specular, emission; + float transparency, shininess; + action->getMaterial(ambient, diffuse, specular, emission, shininess, + transparency, v->getMaterialIndex()); + if (colorBinding == osg::Geometry::BIND_PER_VERTEX) + colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2], + 1.0 - transparency)); + else if (colorBinding == osg::Geometry::BIND_PER_PRIMITIVE && index == 0) + colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2], + 1.0 - transparency)); + } + + // Get the texture coordinates + SbVec4f texCoord = v->getTextureCoords(); + textureCoords.push_back(osg::Vec2(texCoord[0], texCoord[1])); +} + +void ConvertFromInventor::addTriangleCB(void* data, SoCallbackAction* action, + const SoPrimitiveVertex* v0, + const SoPrimitiveVertex* v1, + const SoPrimitiveVertex* v2) +{ + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + switch (thisPtr->vertexOrder) + { + case CLOCKWISE: + thisPtr->addVertex(action, v0, 0); + thisPtr->addVertex(action, v2, 1); + thisPtr->addVertex(action, v1, 2); + break; + case COUNTER_CLOCKWISE: + thisPtr->addVertex(action, v0, 0); + thisPtr->addVertex(action, v1, 1); + thisPtr->addVertex(action, v2, 2); + break; + } + + thisPtr->numPrimitives++; + thisPtr->primitiveType = osg::PrimitiveSet::TRIANGLES; +} + +void ConvertFromInventor::addLineSegmentCB(void* data, SoCallbackAction* action, + const SoPrimitiveVertex* v0, + const SoPrimitiveVertex* v1) +{ + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + thisPtr->addVertex(action, v0, 0); + thisPtr->addVertex(action, v1, 1); + + thisPtr->numPrimitives++; + thisPtr->primitiveType = osg::PrimitiveSet::LINES; +} + +void ConvertFromInventor::addPointCB(void* data, SoCallbackAction* action, + const SoPrimitiveVertex* v0) +{ + ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); + + thisPtr->addVertex(action, v0, 0); + + thisPtr->numPrimitives++; + thisPtr->primitiveType = osg::PrimitiveSet::POINTS; +} diff --git a/src/osgPlugins/Inventor/ConvertFromInventor.h b/src/osgPlugins/Inventor/ConvertFromInventor.h new file mode 100644 index 000000000..5abee3859 --- /dev/null +++ b/src/osgPlugins/Inventor/ConvertFromInventor.h @@ -0,0 +1,108 @@ +#ifndef _CONVERTFROMINVENTOR_H_ +#define _CONVERTFROMINVENTOR_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +class ConvertFromInventor +{ + public: + ConvertFromInventor(); + ~ConvertFromInventor(); + + osg::Node* convert(SoNode* rootIVNode); + + private: + + // Callback functions for converting inventor scene graph to osg + // scene graph + + static SoCallbackAction::Response preShape(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response postShape(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response preGroup(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response postGroup(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response preTexture(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response preLight(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response preRotor(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response prePendulum(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response preShuttle(void* data, + SoCallbackAction* action, const SoNode* node); + static SoCallbackAction::Response preLOD(void* data, + SoCallbackAction* action, const SoNode* node); + + static void addTriangleCB(void* data, SoCallbackAction* action, + const SoPrimitiveVertex *v0, + const SoPrimitiveVertex *v1, + const SoPrimitiveVertex *v2); + static void addLineSegmentCB(void* data, SoCallbackAction* action, + const SoPrimitiveVertex *v0, + const SoPrimitiveVertex *v1); + static void addPointCB(void* data, SoCallbackAction* action, + const SoPrimitiveVertex *v0); + private: + + void addVertex(SoCallbackAction* action, const SoPrimitiveVertex* v, + int index); + + osg::StateSet* getStateSet(SoCallbackAction* action); + + osg::Texture2D* convertIVTexToOSGTex(SoTexture2* soTex, + SoCallbackAction* action); + + void transformLight(SoCallbackAction* action, const SbVec3f& vec, + osg::Vec3& transVec); + + // OSG doesn't seem to have a transpose function for matrices + void transposeMatrix(osg::Matrix& mat); + + private: + + // Normal and color binding + osg::Geometry::AttributeBinding normalBinding; + osg::Geometry::AttributeBinding colorBinding; + + // List of vertices, normals, colors and texture coordinates + std::vector vertices; + std::vector normals; + std::vector colors; + std::vector textureCoords; + + // Num of primitive and primitive type + int numPrimitives; + osg::PrimitiveSet::Mode primitiveType; + + // Vertex ordering + enum VertexOrder { CLOCKWISE, COUNTER_CLOCKWISE }; + VertexOrder vertexOrder; + + // Stack of group nodes (used to build the scene graph) + std::stack groupStack; + + // Stack of texture nodes (used for attaching the right texture to the + // geosets) + std::stack soTexStack; + + // For avoiding duplication of same texture objects + std::map ivToOsgTexMap; + + // Stack to maintain the list of lights at each level of the + // scenegraph + typedef std::vector LightList; + std::stack lightStack; +}; + +#endif diff --git a/src/osgPlugins/Inventor/GNUmakefile b/src/osgPlugins/Inventor/GNUmakefile new file mode 100644 index 000000000..7fe6098a8 --- /dev/null +++ b/src/osgPlugins/Inventor/GNUmakefile @@ -0,0 +1,24 @@ +TOPDIR = ../../.. +include $(TOPDIR)/Make/makedefs + +CXXFILES =\ + ReaderWriterIV.cpp \ + ConvertFromInventor.cpp \ + PendulumCallback.cpp \ + ShuttleCallback.cpp \ + GroupSoLOD.cpp + +ifeq ($(USE_COIN),1) + INVENTOR_LIB = -lCoin +else + INVENTOR_LIB = -lInventor +endif + +INC += -I$(THISDIR) +LIBS += $(OSG_LIBS) $(OTHER_LIBS) $(INVENTOR_LIB) +TARGET_BASENAME = iv + +include $(TOPDIR)/Make/cygwin_plugin_def +PLUGIN = $(PLUGIN_PREFIX)$(TARGET_BASENAME).$(PLUGIN_EXT) + +include $(TOPDIR)/Make/makerules diff --git a/src/osgPlugins/Inventor/GroupSoLOD.cpp b/src/osgPlugins/Inventor/GroupSoLOD.cpp new file mode 100644 index 000000000..12429da28 --- /dev/null +++ b/src/osgPlugins/Inventor/GroupSoLOD.cpp @@ -0,0 +1,28 @@ +#include +#include + +#include "GroupSoLOD.h" + +SO_NODE_SOURCE(GroupSoLOD); + +void GroupSoLOD::initClass() +{ + classTypeId = SoType::overrideType(SoLOD::getClassTypeId(), + createInstance); + parentFieldData = SoLOD::getFieldDataPtr(); +} + +GroupSoLOD::GroupSoLOD() +{ + SO_NODE_CONSTRUCTOR(GroupSoLOD); +} + +GroupSoLOD::~GroupSoLOD() +{ +} + +void GroupSoLOD::callback(SoCallbackAction *action) +{ + SoGroup::doAction(action); +} + diff --git a/src/osgPlugins/Inventor/GroupSoLOD.h b/src/osgPlugins/Inventor/GroupSoLOD.h new file mode 100644 index 000000000..ce2174d6d --- /dev/null +++ b/src/osgPlugins/Inventor/GroupSoLOD.h @@ -0,0 +1,22 @@ +#ifndef _GROUPSOLOD_H_ +#define _GROUPSOLOD_H_ + +#include +#include + +class GroupSoLOD : public SoLOD +{ + SO_NODE_HEADER(GroupSoLOD); + +public: + GroupSoLOD(); + static void initClass(); + +protected: + virtual void callback(SoCallbackAction *action); + +private: + virtual ~GroupSoLOD(); +}; + +#endif diff --git a/src/osgPlugins/Inventor/PendulumCallback.cpp b/src/osgPlugins/Inventor/PendulumCallback.cpp new file mode 100644 index 000000000..c637ce6f9 --- /dev/null +++ b/src/osgPlugins/Inventor/PendulumCallback.cpp @@ -0,0 +1,54 @@ +#include + +#include "PendulumCallback.h" + +PendulumCallback::PendulumCallback(const osg::Vec3& axis, + float startAngle, float endAngle, + float frequency) +{ + _axis = axis; + _startAngle = startAngle; + _endAngle = endAngle; + _frequency = frequency; + + _previousTraversalNumber = -1; + _previousTime = -1.0; + _angle = 0.0; +} + +void PendulumCallback::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (!nv) + return; + + osg::MatrixTransform* transform = dynamic_cast(node); + if (!transform) + return; + + const osg::FrameStamp* fs = nv->getFrameStamp(); + if (!fs) + return; + + // ensure that we do not operate on this node more than + // once during this traversal. This is an issue since node + // can be shared between multiple parents. + if (nv->getTraversalNumber()!=_previousTraversalNumber) + { + double currentTime = fs->getReferenceTime(); + _angle += (currentTime - _previousTime) * 2 * M_PI * _frequency; + + double frac = 0.5 + 0.5 * sin(_angle); + double rotAngle = _endAngle - _startAngle - M_PI + + (1.0 - frac) * _startAngle + frac * _endAngle; + + // update the specified transform + transform->setMatrix(osg::Matrix::rotate(rotAngle, _axis)); + + _previousTraversalNumber = nv->getTraversalNumber(); + _previousTime = currentTime; + } + + // must call any nested node callbacks and continue subgraph traversal. + traverse(node,nv); + +} diff --git a/src/osgPlugins/Inventor/PendulumCallback.h b/src/osgPlugins/Inventor/PendulumCallback.h new file mode 100644 index 000000000..a3455cd41 --- /dev/null +++ b/src/osgPlugins/Inventor/PendulumCallback.h @@ -0,0 +1,29 @@ +#ifndef _PENDULUMCALLBACK_H_ +#define _PENDULUMCALLBACK_H_ + +#include +#include + +// Callback for handling the SoPendulum node +class PendulumCallback : public osg::NodeCallback +{ + public: + + PendulumCallback(const osg::Vec3& axis, float startAngle, + float endAngle, float frequency); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + + protected: + + float _startAngle; + float _endAngle; + float _frequency; + osg::Vec3 _axis; + + int _previousTraversalNumber; + double _previousTime; + float _angle; +}; + +#endif diff --git a/src/osgPlugins/Inventor/ReaderWriterIV.cpp b/src/osgPlugins/Inventor/ReaderWriterIV.cpp new file mode 100644 index 000000000..37cccc3b8 --- /dev/null +++ b/src/osgPlugins/Inventor/ReaderWriterIV.cpp @@ -0,0 +1,63 @@ +#include "ReaderWriterIV.h" + +// OSG headers +#include +#include + +// Inventor headers +#include +#include + +#include "ConvertFromInventor.h" +#include "GroupSoLOD.h" + +// Register with Registry to instantiate the inventor reader. +osgDB::RegisterReaderWriterProxy g_ivReaderWriterProxy; + +ReaderWriterIV::ReaderWriterIV() +{ +} + +// Read file and convert to OSG +osgDB::ReaderWriter::ReadResult +ReaderWriterIV::readNode(const std::string& fileName, + const osgDB::ReaderWriter::Options*) +{ + std::string ext = osgDB::getLowerCaseFileExtension(fileName); + if (!acceptsExtension(ext)) + return ReadResult::FILE_NOT_HANDLED; + + osg::notify(osg::INFO) << "osgDB::ReaderWriterIV::readNode() Reading file " + << fileName.data() << std::endl; + + // Initialize Inventor + SoInteraction::init(); + + // Initial GroupSoLOD node + GroupSoLOD::initClass(); + + // Open the file + SoInput input; + if (!input.openFile(fileName.data())) + { + osg::notify(osg::WARN) << "osgDB::ReaderWriterIV::readIVFile() " + << "Cannot open file " << fileName << std::endl; + return ReadResult::ERROR_IN_READING_FILE; + } + + // Create the inventor scenegraph from the file + SoSeparator* rootIVNode = SoDB::readAll(&input); + + // Close the file + input.closeFile(); + + if (rootIVNode) + { + // Convert the inventor scenegraph to an osg scenegraph and return it + ConvertFromInventor convertIV; + return convertIV.convert(rootIVNode); + } + + return ReadResult::FILE_NOT_HANDLED; +} + diff --git a/src/osgPlugins/Inventor/ReaderWriterIV.h b/src/osgPlugins/Inventor/ReaderWriterIV.h new file mode 100644 index 000000000..096d27fcb --- /dev/null +++ b/src/osgPlugins/Inventor/ReaderWriterIV.h @@ -0,0 +1,28 @@ +#ifndef _READERWRITERIV_H_ +#define _READERWRITERIV_H_ + +#include +#include + +class ReaderWriterIV : public osgDB::ReaderWriter +{ + public: + ReaderWriterIV(); + + virtual const char* className() + { + return "Inventor Reader"; + } + + virtual bool acceptsExtension(const std::string& extension) + { + return osgDB::equalCaseInsensitive(extension, "iv") ? true : + osgDB::equalCaseInsensitive(extension, "wrl") ? true : false; + } + + virtual ReadResult readNode(const std::string& filename, + const osgDB::ReaderWriter::Options *); + +}; + +#endif diff --git a/src/osgPlugins/Inventor/ShuttleCallback.cpp b/src/osgPlugins/Inventor/ShuttleCallback.cpp new file mode 100644 index 000000000..0dc4a4eb1 --- /dev/null +++ b/src/osgPlugins/Inventor/ShuttleCallback.cpp @@ -0,0 +1,53 @@ +#include + +#include "ShuttleCallback.h" + +ShuttleCallback::ShuttleCallback(const osg::Vec3& startPos, + const osg::Vec3& endPos, + float frequency) +{ + _startPos = startPos; + _endPos = endPos; + _frequency = frequency; + + _previousTraversalNumber = -1; + _previousTime = -1.0; + _angle = 0.0; +} + +void ShuttleCallback::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (!nv) + return; + + osg::MatrixTransform* transform = dynamic_cast(node); + if (!transform) + return; + + const osg::FrameStamp* fs = nv->getFrameStamp(); + if (!fs) + return; + + // ensure that we do not operate on this node more than + // once during this traversal. This is an issue since node + // can be shared between multiple parents. + if (nv->getTraversalNumber()!=_previousTraversalNumber) + { + double currentTime = fs->getReferenceTime(); + _angle += (currentTime - _previousTime) * 2 * M_PI * _frequency; + + double frac = 0.5 + 0.5 * sin(_angle); + + osg::Vec3 position = _startPos * (1.0 - frac) + _endPos * frac; + + // update the specified transform + transform->setMatrix(osg::Matrix::translate(position)); + + _previousTraversalNumber = nv->getTraversalNumber(); + _previousTime = currentTime; + } + + // must call any nested node callbacks and continue subgraph traversal. + traverse(node,nv); + +} diff --git a/src/osgPlugins/Inventor/ShuttleCallback.h b/src/osgPlugins/Inventor/ShuttleCallback.h new file mode 100644 index 000000000..34e786341 --- /dev/null +++ b/src/osgPlugins/Inventor/ShuttleCallback.h @@ -0,0 +1,28 @@ +#ifndef _SHUTTLECALLBACK_H_ +#define _SHUTTLECALLBACK_H_ + +#include +#include + +// Callback for handling the SoShuttle node +class ShuttleCallback : public osg::NodeCallback +{ + public: + + ShuttleCallback(const osg::Vec3& startPos, const osg::Vec3& endPos, + float frequency); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + + protected: + + osg::Vec3 _startPos; + osg::Vec3 _endPos; + float _frequency; + + int _previousTraversalNumber; + double _previousTime; + float _angle; +}; + +#endif