#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 #include #include // Inventor headers #include #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 #define DEBUG_IV_PLUGIN /////////////////////////////////////////// ConvertFromInventor::ConvertFromInventor() { numPrimitives = 0; _hasVRMLImageTexture = false; } /////////////////////////////////////////// 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 _root = new osg::MatrixTransform; _root->setMatrix(ivToOSGMat); groupStack.push(_root.get()); // 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); //callback for VRMLImageTextures cbAction.addPreCallback(SoVRMLImageTexture::getClassTypeId(), _vrmlImageTextureAction,this); // Traverse the inventor scene graph cbAction.apply(rootIVNode); // Pop the root osg node groupStack.pop(); lightStack.pop(); return _root.get(); } ////////////////////////////////////////////////////////////////////////////////// SoCallbackAction::Response ConvertFromInventor::_vrmlImageTextureAction(void* data, SoCallbackAction* action, const SoNode* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "_vrmlImageTextureAction() " << node->getTypeId().getName().getString() << std::endl; #endif ///The converter data ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); SoVRMLImageTexture* vit = (SoVRMLImageTexture*)(node); if(vit) { //convert the SoVRMLImageTexture to an osg::Texture thisPtr->_setVRMLImageTexture(vit,action); } return SoCallbackAction::CONTINUE; } /////////////////////////////////////////////////////////////////// SoCallbackAction::Response ConvertFromInventor::preShape(void* data, SoCallbackAction* action, const SoNode* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "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* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "postShape() " << node->getTypeId().getName().getString() << std::endl; #endif ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data); // Create a new Geometry osg::ref_ptr geometry = new osg::Geometry; // Get the modeling matrix osg::Matrix modelMat; modelMat.set((float *)action->getModelMatrix().getValue()); // Tranform the vertices based on the modeling matrix osg::ref_ptr coords = new osg::Vec3Array(thisPtr->vertices.size()); for (unsigned int i = 0; i < thisPtr->vertices.size(); i++) (*coords)[i] = modelMat.preMult(thisPtr->vertices[i]); geometry->setVertexArray(coords.get()); // 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::ref_ptr 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(); } } geometry->setNormalArray(norms.get()); geometry->setNormalBinding(thisPtr->normalBinding); // Set the colors osg::ref_ptr 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]; } geometry->setColorArray(cols.get()); geometry->setColorBinding(thisPtr->colorBinding); #if 0 // original code // BUG: if default texture coordinates are used in Inventor model, // the texture is not shown in OSG if (!(thisPtr->textureCoords.empty()) && action->getNumTextureCoordinates()>0) { osg::notify(osg::NOTICE)<<"tex coords found"<textureCoords.empty())/* && action->getNumTextureCoordinates()>0*/) // BUG: That was avoiding using of automatic texture coordinate generation of IV. #else // improved code if (thisPtr->textureCoords.empty()) osg::notify(osg::NOTICE)<<"tex coords not found"<getNumTextureCoordinates()>0) osg::notify(osg::DEBUG_INFO)<<"tex coords found"<getTextureMatrix().getValue()); // Transform texture coordinates if texture matrix is not an identity mat osg::Matrix identityMat; identityMat.makeIdentity(); osg::ref_ptr 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()); } } geometry->setTexCoordArray(0, texCoords.get()); } // Set the parameters for the geometry geometry->addPrimitiveSet(new osg::DrawArrays(thisPtr->primitiveType,0, coords->size())); // Get the StateSet for the geoset osg::ref_ptr stateSet = thisPtr->getStateSet(action); geometry->setStateSet(stateSet.get()); // Add the geoset to a geode osg::ref_ptr geode = new osg::Geode; geode->addDrawable(geometry.get()); // Add geode to scenegraph thisPtr->groupStack.top()->addChild(geode.get()); return SoCallbackAction::CONTINUE; } /////////////////////////////////////////////////////////////// SoCallbackAction::Response ConvertFromInventor::preTexture(void* data, SoCallbackAction *, const SoNode* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "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 osg::notify(osg::INFO) << "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::ref_ptr 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/osg::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.get()); thisPtr->lightStack.pop(); thisPtr->lightStack.push(lightList); } return SoCallbackAction::CONTINUE; } /////////////////////////////////////////////////////////////////////////////////////// osg::ref_ptr ConvertFromInventor::getStateSet(SoCallbackAction* action) { osg::ref_ptr stateSet = new osg::StateSet; // Inherit modes from the global state stateSet->clear(); 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::ref_ptr transparency = new osg::BlendFunc; stateSet->setAttributeAndModes(transparency.get(), osg::StateAttribute::ON); // Enable depth sorting for transparent objects stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } // Set linewidth if (action->getLineWidth()) { osg::ref_ptr lineWidth = new osg::LineWidth; lineWidth->setWidth(action->getLineWidth()); stateSet->setAttributeAndModes(lineWidth.get(), osg::StateAttribute::ON); } // Set pointsize if (action->getPointSize()) { osg::ref_ptr point = new osg::Point; point->setSize(action->getPointSize()); stateSet->setAttributeAndModes(point.get(), osg::StateAttribute::ON); } // Set draw mode switch (action->getDrawStyle()) { case SoDrawStyle::FILLED: { #if 0 // OSG defaults to filled draw style, so no need to set redundent state. osg::PolygonMode *polygonMode = new osg::PolygonMode; polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL); stateSet->setAttributeAndModes(polygonMode, osg::StateAttribute::ON); #endif break; } case SoDrawStyle::LINES: { osg::ref_ptr polygonMode = new osg::PolygonMode; polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON); break; } case SoDrawStyle::POINTS: { osg::ref_ptr polygonMode = new osg::PolygonMode; polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::POINT); stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON); break; } case SoDrawStyle::INVISIBLE: // check how to handle this in osg. break; } // Set back face culling if (action->getShapeType() == SoShapeHints::SOLID) { osg::ref_ptr cullFace = new osg::CullFace; cullFace->setMode(osg::CullFace::BACK); stateSet->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); } // Set lighting if (action->getLightModel() == SoLightModel::BASE_COLOR) stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); else { // Set the material osg::ref_ptr 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.get(), osg::StateAttribute::ON); stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON); #if 0 // disable as two sided lighting causes problem under NVidia, and the above osg::Material settings are single sided anway.. // Set two sided lighting osg::LightModel* lightModel = new osg::LightModel; lightModel->setTwoSided(true); stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON); #endif // 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 osg::ref_ptr texture; if(_hasVRMLImageTexture) { ///VRMLImageTexture texture = _getConvertedVRMLImageTexture(); _hasVRMLImageTexture = false; stateSet->setTextureAttributeAndModes(0,texture.get(), osg::StateAttribute::ON); // Set the texture environment osg::ref_ptr 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; #ifdef COIN_BASIC_H // This check is a very crude Coin detector. // SGI's Inventor does not have REPLACE mode, but the Coin 3D library does. case SoTexture2::REPLACE: texEnv->setMode(osg::TexEnv::REPLACE); break; #endif } stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON); stateSet->setAttributeAndModes(new osg::ShadeModel()); } else if (soTexStack.top()) { osg::notify(osg::NOTICE)<<"Have texture"< tex; // Found a corresponding OSG texture object if (ivToOsgTexMap[soTexStack.top()]) texture = ivToOsgTexMap[soTexStack.top()]; else { // Create a new osg texture texture = convertIVTexToOSGTex(soTexStack.top(), action); // Add the new texture to the database ivToOsgTexMap[soTexStack.top()] = texture.get(); } stateSet->setTextureAttributeAndModes(0,texture.get(), osg::StateAttribute::ON); // Set the texture environment osg::ref_ptr 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; #ifdef COIN_BASIC_H // This check is a very crude Coin detector. // SGI's Inventor does not have REPLACE mode, but the Coin 3D library does. case SoTexture2::REPLACE: texEnv->setMode(osg::TexEnv::REPLACE); break; #endif } stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON); } else { // fallback because many inventor models don't appear to have any SoTexture2.. SbVec2s soTexSize; int soTexNC; const unsigned char* texImage = action->getTextureImage(soTexSize, soTexNC); if (texImage) { osg::notify(osg::NOTICE)<<"Image data found soTexSize[0]="< "; if (str[0]=='\"') str.erase(str.begin()); if (str[str.size()-1]=='\"') str.erase(str.begin()+str.size()-1); osg::notify(osg::INFO) << str << std::endl; osgTexImage->setFileName(str); #endif 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*/); // BUG: -1 have to be removed (definitely WRONG packing!) It causes crashes of GLU. // Create the osg texture texture = new osg::Texture2D; texture->setImage(osgTexImage.get()); static std::map texWrapMap2; static bool firstTime2 = true; if (firstTime2) { texWrapMap2[SoTexture2::CLAMP] = osg::Texture2D::CLAMP; texWrapMap2[SoTexture2::REPEAT] = osg::Texture2D::REPEAT; firstTime2 = false; } // Set texture wrap mode texture->setWrap(osg::Texture2D::WRAP_S,texWrapMap2[action->getTextureWrapS()]); texture->setWrap(osg::Texture2D::WRAP_T,texWrapMap2[action->getTextureWrapT()]); stateSet->setTextureAttributeAndModes(0,texture.get(), osg::StateAttribute::ON); // Set the texture environment osg::ref_ptr 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; #ifdef COIN_BASIC_H // This check is a very crude Coin detector. // SGI's Inventor does not have REPLACE mode, but the Coin 3D library does. case SoTexture2::REPLACE: texEnv->setMode(osg::TexEnv::REPLACE); break; #endif } stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON); } } return stateSet; } //////////////////////////////////////////////////////////////////// osg::Texture2D* ConvertFromInventor::convertIVTexToOSGTex(SoTexture2* soTex, SoCallbackAction* action) { osg::notify(osg::NOTICE)<<"convertIVTexToOSGTex"<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::ref_ptr osgTexImage = new osg::Image; SbString iv_string; soTex->filename.get(iv_string); std::string str(iv_string.getString()); osg::notify(osg::INFO) << str << " -> "; if (str[0]=='\"') str.erase(str.begin()); if (str[str.size()-1]=='\"') str.erase(str.begin()+str.size()-1); osg::notify(osg::INFO) << str << std::endl; osgTexImage->setFileName(str); 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*/); // BUG: -1 have to be removed (definitely WRONG packing!) It causes crashes of GLU. // Create the osg texture osg::ref_ptr osgTex = new osg::Texture2D; osgTex->setImage(osgTexImage.get()); 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.get(); } /////////////////////////////////////////////////////////////////// SoCallbackAction::Response ConvertFromInventor::preGroup(void* data, SoCallbackAction* action, const SoNode* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "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::ref_ptr group = new osg::Group; thisPtr->groupStack.top()->addChild(group.get()); thisPtr->groupStack.push(group.get()); 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 osg::notify(osg::INFO) << "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::ref_ptr group = thisPtr->groupStack.top(); while (strcmp(group->className(), "MatrixTransform") == 0) { thisPtr->groupStack.pop(); thisPtr->groupStack.top()->addChild(group.get()); 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.get()); // 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 osg::notify(osg::INFO) << "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::ref_ptr lod = new osg::LOD; thisPtr->groupStack.push(lod.get()); thisPtr->groupStack.top()->addChild(lod.get()); // 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 osg::notify(osg::INFO) << "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::ref_ptr 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]); osg::ref_ptr rotorCallback = new osgUtil::TransformCallback(pivot, axis, 2 * osg::PI * ivRotor->speed.getValue()); // Set the app callback rotorTransform->setUpdateCallback(rotorCallback.get()); // Push the rotor transform onto the group stack thisPtr->groupStack.push(rotorTransform.get()); thisPtr->groupStack.top()->addChild(rotorTransform.get()); return SoCallbackAction::CONTINUE; } //////////////////////////////////////////////////////////////// SoCallbackAction::Response ConvertFromInventor::prePendulum(void* data, SoCallbackAction *, const SoNode* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "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::ref_ptr 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.get()); thisPtr->groupStack.top()->addChild(pendulumTransform.get()); return SoCallbackAction::CONTINUE; } //////////////////////////////////////////////////////////////// SoCallbackAction::Response ConvertFromInventor::preShuttle(void* data, SoCallbackAction *, const SoNode* node) { #ifdef DEBUG_IV_PLUGIN osg::notify(osg::INFO) << "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::ref_ptr 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.get()); thisPtr->groupStack.top()->addChild(shuttleTransform.get()); 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; } ////////////////////////////////////////////////////////////////////// void ConvertFromInventor::_setVRMLImageTexture(const SoVRMLImageTexture* vit, SoCallbackAction* action) { _hasVRMLImageTexture = true; ///Coin API to extract VRML97 ImageTexture int nComponents = 1; SbImage* vitImage = (SbImage*)vit->getImage(); SbString filename; filename = vit->url.getValues(0)[0]; vitImage->readFile(filename); SbVec2s dimensions; dimensions[0] = 2; dimensions[1] = 2; const unsigned char* dataPtr = vitImage->getValue(dimensions,nComponents); unsigned char* data = new unsigned char[dimensions[0]* dimensions[1]* nComponents]; ///Is this effiecient??? memcpy(data, dataPtr, dimensions[0]*dimensions[1]*nComponents); GLenum format = GL_RGBA; switch (nComponents) { case 1: format = GL_LUMINANCE; break; case 2: format = GL_LUMINANCE_ALPHA; break; case 3: format = GL_RGB; break; case 4: default: format = GL_RGBA; break; }; osg::ref_ptr image = new osg::Image(); image->setImage(dimensions[0], dimensions[1], 1, nComponents, format, GL_UNSIGNED_BYTE, const_cast(data), osg::Image::USE_NEW_DELETE); osg::ref_ptr texture = new osg::Texture2D(); texture->setImage(image.get()); osg::Texture::WrapMode smode = (vit->repeatS.getValue())?(osg::Texture::REPEAT):(osg::Texture::CLAMP); osg::Texture::WrapMode tmode = (vit->repeatT.getValue())?(osg::Texture::REPEAT):(osg::Texture::CLAMP); // Set texture wrap mode texture->setWrap(osg::Texture2D::WRAP_S,smode); texture->setWrap(osg::Texture2D::WRAP_T,tmode); _currentVRMLImageTexture = texture; _currentVRMLImageTexture->dirtyTextureObject(); } //////////////////////////////////////////////////////////////////// osg::Texture2D* ConvertFromInventor::_getConvertedVRMLImageTexture() { if(_currentVRMLImageTexture.valid()) { return _currentVRMLImageTexture.get(); } return 0; }