SoNode* ViewProviderDocumentObject::findFrontRootOfType(const SoType& type) const { // first get the document this object is part of and get its GUI counterpart App::Document* pAppDoc = pcObject->getDocument(); Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc); SoSearchAction searchAction; searchAction.setType(type); searchAction.setInterest(SoSearchAction::FIRST); // search in all view providers for the node type std::vector<App::DocumentObject*> obj = pAppDoc->getObjects(); for (std::vector<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it) { const ViewProvider* vp = pGuiDoc->getViewProvider(*it); // Ignore 'this' view provider. It could also happen that vp is 0, e.g. when // several objects have been added to the App::Document before notifying the // Gui::Document if (!vp || vp == this) continue; SoSeparator* front = vp->getFrontRoot(); //if (front && front->getTypeId() == type) // return front; if (front) { searchAction.apply(front); SoPath* path = searchAction.getPath(); if (path) return path->getTail(); } } return 0; }
void ViewProviderVRMLObject::getLocalResources(SoNode* node, std::list<std::string>& resources) { // search for SoVRMLInline files SoSearchAction sa; sa.setType(SoVRMLInline::getClassTypeId()); sa.setInterest(SoSearchAction::ALL); sa.setSearchingAll(true); sa.apply(node); const SoPathList & pathlist = sa.getPaths(); for (int i = 0; i < pathlist.getLength(); i++ ) { SoPath * path = pathlist[i]; SoVRMLInline * vrml = static_cast<SoVRMLInline*>(path->getTail()); const SbString& url = vrml->getFullURLName(); if (url.getLength() > 0) { // add the resource file if not yet listed if (std::find(resources.begin(), resources.end(), url.getString()) == resources.end()) { resources.push_back(url.getString()); } // if the resource file could be loaded check if it references further resources if (vrml->getChildData()) { getLocalResources(vrml->getChildData(), resources); } } } // search for SoVRMLImageTexture, ... files getResourceFile<SoVRMLImageTexture >(node, resources); getResourceFile<SoVRMLMovieTexture >(node, resources); getResourceFile<SoVRMLScript >(node, resources); getResourceFile<SoVRMLBackground >(node, resources); getResourceFile<SoVRMLAudioClip >(node, resources); getResourceFile<SoVRMLAnchor >(node, resources); }
IvDragger::IvDragger(QtCoinViewerPtr viewer, ItemPtr pItem, float draggerScale) { _selectedItem = pItem; _viewer = viewer; _scale = draggerScale; _penv = viewer->GetEnv(); //_ptext = NULL; // set some default behavioral options _checkCollision = false; _prevtransparency = pItem->GetIvTransparency()->value; pItem->GetIvTransparency()->value = SoGLRenderAction::SCREEN_DOOR; if( !!pItem &&(pItem->GetIvRoot() != NULL)) { _GetBounds(pItem->GetIvRoot(), _ab); // make the item transparent SoSearchAction search; search.setType(SoMaterial::getClassTypeId()); search.setInterest(SoSearchAction::ALL); search.apply(pItem->GetIvRoot()); for(int i = 0; i < search.getPaths().getLength(); ++i) { SoPath* path = search.getPaths()[i]; SoMaterial* pmtrl = (SoMaterial*)path->getTail(); vtransparency.push_back(pmtrl->transparency[0]); pmtrl->transparency = 0.25f; } _vlinkaxes.resize(pItem->GetNumIvLinks()); for(size_t i = 0; i < _vlinkaxes.size(); ++i) { _vlinkaxes[i] = _CreateAxes(i == 0 ? 1.0f : 0.25f,0.5f); pItem->GetIvLink(i)->addChild(_vlinkaxes[i]); } } }
void SoBoxSelectionRenderAction::apply(SoNode * node) { SoGLRenderAction::apply(node); if (this->hlVisible) { if (PRIVATE(this)->searchaction == NULL) { PRIVATE(this)->searchaction = new SoSearchAction; } PRIVATE(this)->searchaction->setType(SoFCSelection::getClassTypeId()); PRIVATE(this)->searchaction->setInterest(SoSearchAction::ALL); PRIVATE(this)->searchaction->apply(node); const SoPathList & pathlist = PRIVATE(this)->searchaction->getPaths(); if (pathlist.getLength() > 0) { for (int i = 0; i < pathlist.getLength(); i++ ) { SoPath * path = pathlist[i]; assert(path); SoFCSelection * selection = (SoFCSelection *) path->getTail(); assert(selection->getTypeId().isDerivedFrom(SoFCSelection::getClassTypeId())); if (selection->selected.getValue() && selection->style.getValue() == SoFCSelection::BOX) { PRIVATE(this)->basecolor->rgb.setValue(selection->colorSelection.getValue()); if (PRIVATE(this)->selectsearch == NULL) { PRIVATE(this)->selectsearch = new SoSearchAction; } PRIVATE(this)->selectsearch->setType(SoShape::getClassTypeId()); PRIVATE(this)->selectsearch->setInterest(SoSearchAction::FIRST); PRIVATE(this)->selectsearch->apply(selection); SoPath* shapepath = PRIVATE(this)->selectsearch->getPath(); if (shapepath) { SoPathList list; list.append(shapepath); this->drawBoxes(path, &list); } PRIVATE(this)->selectsearch->reset(); } else if (selection->isHighlighted() && selection->selected.getValue() == SoFCSelection::NOTSELECTED && selection->style.getValue() == SoFCSelection::BOX) { PRIVATE(this)->basecolor->rgb.setValue(selection->colorHighlight.getValue()); if (PRIVATE(this)->selectsearch == NULL) { PRIVATE(this)->selectsearch = new SoSearchAction; } PRIVATE(this)->selectsearch->setType(SoShape::getClassTypeId()); PRIVATE(this)->selectsearch->setInterest(SoSearchAction::FIRST); PRIVATE(this)->selectsearch->apply(selection); SoPath* shapepath = PRIVATE(this)->selectsearch->getPath(); if (shapepath) { SoPathList list; list.append(shapepath); PRIVATE(this)->highlightPath = path; PRIVATE(this)->highlightPath->ref(); this->drawBoxes(path, &list); } PRIVATE(this)->selectsearch->reset(); } } } PRIVATE(this)->searchaction->reset(); } }
SoCamera * SoSceneTextureCubeMapP::findCamera(void) { SoSearchAction sa; sa.setType(SoCamera::getClassTypeId()); sa.setInterest(SoSearchAction::FIRST); sa.apply(PUBLIC(this)->scene.getValue()); SoPath * path = sa.getPath(); if (path == NULL) return NULL; else return (SoCamera *)path->getTail(); }
void AlignmentGroup::setRandomColor() { std::vector<Gui::ViewProviderDocumentObject*>::iterator it; for (it = this->_views.begin(); it != this->_views.end(); ++it) { float r = /*(float)rand()/(float)RAND_MAX*/0.0f; float g = (float)rand()/(float)RAND_MAX; float b = (float)rand()/(float)RAND_MAX; if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) { SoSearchAction searchAction; searchAction.setType(SoMaterial::getClassTypeId()); searchAction.setInterest(SoSearchAction::FIRST); searchAction.apply((*it)->getRoot()); SoPath* selectionPath = searchAction.getPath(); if (selectionPath) { SoMaterial* material = static_cast<SoMaterial*>(selectionPath->getTail()); material->diffuseColor.setValue(r, g, b); } } } }
IvDragger::~IvDragger() { ItemPtr selectedItem = GetSelectedItem(); if( !!selectedItem &&(selectedItem->GetIvRoot() != NULL)) { for(size_t i = 0; i < _vlinkaxes.size(); ++i) { selectedItem->GetIvLink(i)->removeChild(_vlinkaxes[i]); } _vlinkaxes.clear(); // revert transparency SoSearchAction search; search.setType(SoMaterial::getClassTypeId()); search.setInterest(SoSearchAction::ALL); search.apply(selectedItem->GetIvRoot()); for(int i = 0; i < search.getPaths().getLength(); ++i) { SoPath* path = search.getPaths()[i]; SoMaterial* pmtrl = (SoMaterial*)path->getTail(); if( i < (int)vtransparency.size() ) pmtrl->transparency = vtransparency[i]; } selectedItem->GetIvTransparency()->value = _prevtransparency; } }
////////////////////////////////////////////////////////////////////////////// // // beginTraversal - have the base class render the passed scene graph, // then render highlights for our selection node. // void SoLineHighlightRenderAction::apply(SoNode *node) // ////////////////////////////////////////////////////////////////////////////// { // Render the scene SoGLRenderAction::apply(node); // Render the highlight? if (! hlVisible) return; // Add the rendering localRoot beneath our local scene graph localRoot // so that we can find a path from localRoot to the selection node // which is under the render root. localRoot->addChild(node); // Find the selection node under the local root static SoSearchAction *sa = NULL; if (sa == NULL) sa = new SoSearchAction; else sa->reset(); sa->setFind(SoSearchAction::TYPE); sa->setInterest(SoSearchAction::FIRST); sa->setType(SoSelection::getClassTypeId()); sa->apply(localRoot); SoPath *hlPath = sa->getPath(); if (hlPath != NULL) { hlPath = hlPath->copy(); hlPath->ref(); // Make sure something is selected SoSelection *sel = (SoSelection *) hlPath->getTail(); if (sel->getNumSelected() > 0) { // Keep the length from the root to the selection // as an optimization so we can reuse this data int reusablePathLength = hlPath->getLength(); // For each selection path, create a new path rooted under our localRoot for (int j = 0; j < sel->getNumSelected(); j++) { // Continue the path down to the selected object. // No need to deal with p[0] since that is the sel node. SoFullPath *p = (SoFullPath *) sel->getPath(j); SoNode *pathTail = p->getTail(); if ( pathTail->isOfType(SoBaseKit::getClassTypeId())) { // Find the last nodekit on the path. SoNode *kitTail = ((SoNodeKitPath *)p)->getTail(); // Extend the selectionPath until it reaches this last kit. SoFullPath *fp = (SoFullPath *) p; int k = 0; do { hlPath->append(fp->getIndex(++k)); } while ( fp->getNode(k) != kitTail ); } else { for (int k = 1; k < p->getLength(); k++) hlPath->append(p->getIndex(k)); } // Render the shape with the local draw style to make the highlight SoGLRenderAction::apply(hlPath); // Restore hlPath for reuse hlPath->truncate(reusablePathLength); } } hlPath->unref(); } // Remove the rendering localRoot from our local scene graph localRoot->removeChild(node); }
static SoSeparator * setUpGraph(const SbViewportRegion &vpReg, SoInput *sceneInput, Options &options) // ////////////////////////////////////////////////////////////// { // Create a root separator to hold everything. Turn // caching off, since the transformation will blow // it anyway. SoSeparator *root = new SoSeparator; root->ref(); root->renderCaching = SoSeparator::OFF; // Add a camera to view the scene SoPerspectiveCamera *camera = new SoPerspectiveCamera; root->addChild(camera); // Add a transform node to spin the scene SoTransform *sceneTransform = new SoTransform; sceneTransform->setName(SCENE_XFORM_NAME); root->addChild(sceneTransform); // Read and add input scene graph SoSeparator *inputRoot = SoDB::readAll(sceneInput); if (inputRoot == NULL) { fprintf(stderr, "Cannot read scene graph\n"); root->unref(); exit(1); } root->addChild(inputRoot); SoPath *path; SoGroup *parent, *group; SoSearchAction act; // expand out all File nodes and replace them with groups // containing the children SoFile *fileNode; act.setType(SoFile::getClassTypeId()); act.setInterest(SoSearchAction::FIRST); act.apply(inputRoot); while ((path = act.getPath()) != NULL) { fileNode = (SoFile *) path->getTail(); path->pop(); parent = (SoGroup *) path->getTail(); group = fileNode->copyChildren(); if (group) { parent->replaceChild(fileNode, group); // apply action again and continue act.apply(inputRoot); } } // expand out all node kits and replace them with groups // containing the children SoBaseKit *kitNode; SoChildList *childList; act.setType(SoBaseKit::getClassTypeId()); act.setInterest(SoSearchAction::FIRST); act.apply(inputRoot); while ((path = act.getPath()) != NULL) { kitNode = (SoBaseKit *) path->getTail(); path->pop(); parent = (SoGroup *) path->getTail(); group = new SoGroup; childList = kitNode->getChildren(); for (int i=0; i<childList->getLength(); i++) group->addChild((*childList)[i]); parent->replaceChild(kitNode, group); act.apply(inputRoot); } // check to see if there are any lights // if no lights, add a directional light to the scene act.setType(SoLight::getClassTypeId()); act.setInterest(SoSearchAction::FIRST); act.apply(inputRoot); if (act.getPath() == NULL) { // no lights SoDirectionalLight *light = new SoDirectionalLight; root->insertChild(light, 1); } else options.hasLights = TRUE; // check to see if there are any texures in the scene act.setType(SoTexture2::getClassTypeId()); act.setInterest(SoSearchAction::FIRST); act.apply(inputRoot); if (act.getPath() != NULL) options.hasTextures = TRUE; camera->viewAll(root, vpReg); // print out information about the scene graph int32_t numTris, numLines, numPoints, numNodes; countPrimitives( inputRoot, numTris, numLines, numPoints, numNodes ); printf("Number of nodes in scene graph: %d\n", numNodes ); printf("Number of triangles in scene graph: %d\n", numTris ); printf("Number of lines in scene graph: %d\n", numLines ); printf("Number of points in scene graph: %d\n\n", numPoints ); // Make the center of rotation the center of // the scene SoGetBoundingBoxAction bba(vpReg); bba.apply(root); sceneTransform->center = bba.getBoundingBox().getCenter(); return root; }
void ViewProviderRobotObject::updateData(const App::Property* prop) { Robot::RobotObject* robObj = static_cast<Robot::RobotObject*>(pcObject); if (prop == &robObj->RobotVrmlFile) { // read also from file const char* filename = robObj->RobotVrmlFile.getValue(); QString fn = QString::fromUtf8(filename); QFile file(fn); SoInput in; pcRobotRoot->removeAllChildren(); if (!fn.isEmpty() && file.open(QFile::ReadOnly)) { QByteArray buffer = file.readAll(); in.setBuffer((void *)buffer.constData(), buffer.length()); SoSeparator * node = SoDB::readAll(&in); if (node) pcRobotRoot->addChild(node); pcRobotRoot->addChild(pcTcpRoot); } // search for the conection points +++++++++++++++++++++++++++++++++++++++++++++++++ Axis1Node = Axis2Node = Axis3Node = Axis4Node = Axis5Node = Axis6Node = 0; SoSearchAction searchAction; SoPath * path; // Axis 1 searchAction.setName("FREECAD_AXIS1"); searchAction.setInterest(SoSearchAction::FIRST); searchAction.setSearchingAll(FALSE); searchAction.apply(pcRobotRoot); path = searchAction.getPath(); if(path){ SoNode* node = path->getTail(); std::string typeName = (const char*)node->getTypeId().getName(); if (!node || node->getTypeId() != SoVRMLTransform::getClassTypeId()) throw; // should not happen Axis1Node = static_cast<SoVRMLTransform *>(node); } // Axis 2 searchAction.setName("FREECAD_AXIS2"); searchAction.setInterest(SoSearchAction::FIRST); searchAction.setSearchingAll(FALSE); searchAction.apply(pcRobotRoot); path = searchAction.getPath(); if(path){ SoNode* node = path->getTail(); std::string typeName = (const char*)node->getTypeId().getName(); if (!node || node->getTypeId() != SoVRMLTransform::getClassTypeId()) throw; // should not happen Axis2Node = static_cast<SoVRMLTransform *>(node); } // Axis 3 searchAction.setName("FREECAD_AXIS3"); searchAction.setInterest(SoSearchAction::FIRST); searchAction.setSearchingAll(FALSE); searchAction.apply(pcRobotRoot); path = searchAction.getPath(); if(path){ SoNode* node = path->getTail(); std::string typeName = (const char*)node->getTypeId().getName(); if (!node || node->getTypeId() != SoVRMLTransform::getClassTypeId()) throw; // should not happen Axis3Node = static_cast<SoVRMLTransform *>(node); } // Axis 4 searchAction.setName("FREECAD_AXIS4"); searchAction.setInterest(SoSearchAction::FIRST); searchAction.setSearchingAll(FALSE); searchAction.apply(pcRobotRoot); path = searchAction.getPath(); if(path){ SoNode* node = path->getTail(); std::string typeName = (const char*)node->getTypeId().getName(); if (!node || node->getTypeId() != SoVRMLTransform::getClassTypeId()) throw; // should not happen Axis4Node = static_cast<SoVRMLTransform *>(node); } // Axis 5 searchAction.setName("FREECAD_AXIS5"); searchAction.setInterest(SoSearchAction::FIRST); searchAction.setSearchingAll(FALSE); searchAction.apply(pcRobotRoot); path = searchAction.getPath(); if(path){ SoNode* node = path->getTail(); std::string typeName = (const char*)node->getTypeId().getName(); if (!node || node->getTypeId() != SoVRMLTransform::getClassTypeId()) throw; // should not happen Axis5Node = static_cast<SoVRMLTransform *>(node); } // Axis 6 searchAction.setName("FREECAD_AXIS6"); searchAction.setInterest(SoSearchAction::FIRST); searchAction.setSearchingAll(FALSE); searchAction.apply(pcRobotRoot); path = searchAction.getPath(); if(path){ SoNode* node = path->getTail(); std::string typeName = (const char*)node->getTypeId().getName(); if (!node || node->getTypeId() != SoVRMLTransform::getClassTypeId()) throw; // should not happen Axis6Node = static_cast<SoVRMLTransform *>(node); } if(Axis1Node) Axis1Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis1.getValue()*(M_PI/180)); if(Axis2Node) Axis2Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis2.getValue()*(M_PI/180)); if(Axis3Node) Axis3Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis3.getValue()*(M_PI/180)); if(Axis4Node) Axis4Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis4.getValue()*(M_PI/180)); if(Axis5Node) Axis5Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis5.getValue()*(M_PI/180)); if(Axis6Node) Axis6Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis6.getValue()*(M_PI/180)); }else if (prop == &robObj->Axis1) { if(Axis1Node){ Axis1Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis1.getValue()*(M_PI/180)); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); } }else if (prop == &robObj->Axis2) { if(Axis2Node){ Axis2Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis2.getValue()*(M_PI/180)); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); } }else if (prop == &robObj->Axis3) { if(Axis3Node){ Axis3Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis3.getValue()*(M_PI/180)); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); } }else if (prop == &robObj->Axis4) { if(Axis4Node){ Axis4Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis4.getValue()*(M_PI/180)); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); } }else if (prop == &robObj->Axis5) { if(Axis5Node){ Axis5Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis5.getValue()*(M_PI/180)); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); } }else if (prop == &robObj->Axis6) { if(Axis6Node){ Axis6Node->rotation.setValue(SbVec3f(0.0,1.0,0.0),robObj->Axis6.getValue()*(M_PI/180)); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); } }else if (prop == &robObj->Tcp) { Base::Placement loc = robObj->Tcp.getValue(); SbMatrix M; M.setTransform(SbVec3f(loc.getPosition().x,loc.getPosition().y,loc.getPosition().z), SbRotation(loc.getRotation()[0],loc.getRotation()[1],loc.getRotation()[2],loc.getRotation()[3]), SbVec3f(150,150,150) ); if(pcDragger) pcDragger->setMotionMatrix(M); if(toolShape) toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); //pcTcpTransform->translation = SbVec3f(loc.getPosition().x,loc.getPosition().y,loc.getPosition().z); //pcTcpTransform->rotation = SbRotation(loc.getRotation()[0],loc.getRotation()[1],loc.getRotation()[2],loc.getRotation()[3]); }else if (prop == &robObj->ToolShape) { App::DocumentObject* o = robObj->ToolShape.getValue<App::DocumentObject*>(); if(o && (o->isDerivedFrom(Part::Feature::getClassTypeId()) || o->isDerivedFrom(App::VRMLObject::getClassTypeId())) ){ //Part::Feature *p = dynamic_cast<Part::Feature *>(o); toolShape = Gui::Application::Instance->getViewProvider(o); toolShape->setTransformation((robObj->Tcp.getValue() * (robObj->ToolBase.getValue().inverse())).toMatrix()); }else toolShape = 0; } }
int main(int argc, char ** argv) { if ( argc != 3 ) { fprintf(stderr, "Usage: %s <infile.iv> <outfile.iv>\n", argv[0]); return -1; } SoDB::init(); SoNodeKit::init(); SoInteraction::init(); SoGenerateSceneGraphAction::initClass(); SoTweakAction::initClass(); SoInput in; SoNode * scene, * graph; if ( !in.openFile(argv[1]) ) { fprintf(stderr, "%s: error opening \"%s\" for reading.\n", argv[0], argv[1]); return -1; } scene = SoDB::readAll(&in); if ( scene == NULL ) { fprintf(stderr, "%s: error parsing \"%s\"\n", argv[0], argv[1]); return -1; } scene->ref(); SoGenerateSceneGraphAction action; // action.setDropTypeIfNameEnabled(TRUE); action.apply(scene); graph = action.getGraph(); if ( graph == NULL ) { fprintf(stderr, "%s: error generating scene graph\n", argv[0]); return -1; } graph->ref(); scene->unref(); scene = NULL; // figure out camera settings and needed rendering canvas size SoGetBoundingBoxAction bbaction(SbViewportRegion(64,64)); // just something bbaction.apply(graph); SbBox3f bbox = bbaction.getBoundingBox(); SbVec3f min = bbox.getMin(); SbVec3f max = bbox.getMax(); float bwidth = max[0] - min[0]; float bheight = max[1] - min[1]; // fprintf(stdout, "min: %g %g %g\n", min[0], min[1], min[2]); // fprintf(stdout, "max: %g %g %g\n", max[0], max[1], max[2]); // place camera SoSearchAction search; search.setType(SoCamera::getClassTypeId()); search.setInterest(SoSearchAction::FIRST); search.apply(graph); SoPath * campath = search.getPath(); SoOrthographicCamera * cam = (SoOrthographicCamera *) campath->getTail(); assert(cam != NULL); SbVec3f pos = cam->position.getValue(); cam->position.setValue(SbVec3f(min[0] + ((max[0]-min[0])/2.0), min[1] + ((max[1]-min[1])/2.0), pos[2])); cam->height.setValue(bheight); if ( TRUE ) { // FIXME: only write .iv-scene if asked SoOutput out; if ( !out.openFile(argv[2]) ) { fprintf(stderr, "%s: error opening \"%s\" for writing.\n", argv[0], argv[2]); return -1; } SoWriteAction writer(&out); // writer.setCoinFormattingEnabled(TRUE); writer.apply(graph); } int width = (int) ceil(bwidth * 150.0) + 2; int height = (int) ceil(bheight * 150.0); fprintf(stderr, "image: %d x %d\n", width, height); if ( TRUE ) { // FIXME: only write image if asked SoOffscreenRenderer renderer(SbViewportRegion(width, height)); SoGLRenderAction * glra = renderer.getGLRenderAction(); glra->setNumPasses(9); // FIXME: auto-crop image afterwards? seems like it's a perfect fit right now renderer.setComponents(SoOffscreenRenderer::RGB_TRANSPARENCY); renderer.setBackgroundColor(SbColor(1.0,1.0,1.0)); renderer.render(graph); // FIXME: support command line option filename // FIXME: also support .eps renderer.writeToFile("output.png", "png"); } graph->unref(); return 0; }