void IfReplacer::replaceMaterials(SoNode *sceneRoot, const SoType &typeToReplace) { // Find all nodes of the given type SoSearchAction sa; sa.setType(typeToReplace); sa.setInterest(SoSearchAction::ALL); sa.apply(sceneRoot); // Replace the tail of each path with a material. To do this, we // need to apply an SoCallbackAction to the path to gather the // material components. for (int i = 0; i < sa.getPaths().getLength(); i++) { // Cast the path to a full path, just in case SoFullPath *path = (SoFullPath *) sa.getPaths()[i]; ASSERT(path->getTail()->isOfType(typeToReplace)); // The path better have at least one group above the material if (path->getLength() < 2 || ! path->getNodeFromTail(1)->isOfType(SoGroup::getClassTypeId())) continue; // Create a material node that represents the material in // effect at the tail of the path SoMaterial *newMaterial = createMaterialForPath(path); newMaterial->ref(); // Replace the tail node with that material SoGroup *parent = (SoGroup *) path->getNodeFromTail(1); parent->replaceChild(path->getTail(), newMaterial); newMaterial->unref(); } }
void SoBoxHighlightRenderAction::drawBoxes(SoPath * pathtothis, const SoPathList * pathlist) { int i; int thispos = reclassify_cast<SoFullPath *>(pathtothis)->getLength()-1; assert(thispos >= 0); PRIVATE(this)->postprocpath->setHead(pathtothis->getHead()); // reset for (i = 1; i < thispos; i++) { PRIVATE(this)->postprocpath->append(pathtothis->getIndex(i)); } // we need to disable accumulation buffer antialiasing while // rendering selected objects int oldnumpasses = this->getNumPasses(); this->setNumPasses(1); SoState * thestate = this->getState(); thestate->push(); for (i = 0; i < pathlist->getLength(); i++) { SoFullPath * path = reclassify_cast<SoFullPath *>((*pathlist)[i]); PRIVATE(this)->postprocpath->append(path->getHead()); for (int j = 1; j < path->getLength(); j++) { PRIVATE(this)->postprocpath->append(path->getIndex(j)); } // Previously SoGLRenderAction was used to draw the bounding boxes // of shapes in selection paths, by overriding renderstyle state // elements to lines drawstyle and simply doing: // // SoGLRenderAction::apply(PRIVATE(this)->postprocpath); // Bug // // This could have the unwanted side effect of rendering // non-selected shapes, as they could be part of the path (due to // being placed below SoGroup nodes (instead of SoSeparator // nodes)) up to the selected shape. // // // A better approach turned out to be to soup up and draw only the // bounding boxes of the selected shapes: PRIVATE(this)->drawHighlightBox(PRIVATE(this)->postprocpath); // Remove temporary path from path buffer PRIVATE(this)->postprocpath->truncate(thispos); } this->setNumPasses(oldnumpasses); thestate->pop(); }
////////////////////////////////////////////////////////////////////////////// // // 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); }
// doc from parent void SoFCSelection::handleEvent(SoHandleEventAction * action) { static char buf[513]; HighlightModes mymode = (HighlightModes) this->highlightMode.getValue(); const SoEvent * event = action->getEvent(); #ifdef NO_FRONTBUFFER // mouse move events for preselection if (event->isOfType(SoLocation2Event::getClassTypeId())) { // NOTE: If preselection is off then we do not check for a picked point because otherwise this search may slow // down extremely the system on really big data sets. In this case we just check for a picked point if the data // set has been selected. if (mymode == AUTO || mymode == ON) { const SoPickedPoint * pp = this->getPickedPoint(action); if (pp && pp->getPath()->containsPath(action->getCurPath())) { if (!highlighted) { if (Gui::Selection().setPreselect(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2])){ SoFCSelection::turnoffcurrent(action); SoFCSelection::currenthighlight = (SoFullPath*)action->getCurPath()->copy(); SoFCSelection::currenthighlight->ref(); highlighted = TRUE; this->touch(); // force scene redraw this->redrawHighlighted(action, TRUE); } } snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); getMainWindow()->showMessage(QString::fromAscii(buf),3000); } else { // picked point if (highlighted) { if (mymode == AUTO) SoFCSelection::turnoffcurrent(action); //FIXME: I think we should set 'highlighted' to false whenever no point is picked //else highlighted = FALSE; Gui::Selection().rmvPreselect(); } } } } // key press events else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) { SoKeyboardEvent * const e = (SoKeyboardEvent *) event; if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT) || SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT) ) bShift = true; if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT) || SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT) ) bShift = false; if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL) || SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL) ) bCtrl = true; if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) || SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) ) bCtrl = false; } // mouse press events for (de)selection else if (event->isOfType(SoMouseButtonEvent::getClassTypeId())) { SoMouseButtonEvent * const e = (SoMouseButtonEvent *) event; if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) { //FIXME: Shouldn't we remove the preselection for newly selected objects? // Otherwise the tree signals that an object is preselected even though it is hidden. (Werner) const SoPickedPoint * pp = this->getPickedPoint(action); if (pp && pp->getPath()->containsPath(action->getCurPath())) { if (bCtrl) { if (Gui::Selection().isSelected(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString())) { Gui::Selection().rmvSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString()); } else { Gui::Selection().addSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); if (mymode == OFF) { snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); getMainWindow()->showMessage(QString::fromAscii(buf),3000); } } } else { // Ctrl if (!Gui::Selection().isSelected(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString())) { Gui::Selection().clearSelection(documentName.getValue().getString()); Gui::Selection().addSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); } else { Gui::Selection().clearSelection(documentName.getValue().getString()); Gui::Selection().addSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,0 ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); } if (mymode == OFF) { snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); getMainWindow()->showMessage(QString::fromAscii(buf),3000); } } action->setHandled(); } // picked point } // mouse release } inherited::handleEvent(action); #else // If we don't need to pick for locate highlighting, // then just behave as separator and return. // NOTE: we still have to pick for ON even though we don't have // to re-render, because the app needs to be notified as the mouse // goes over locate highlight nodes. //if (highlightMode.getValue() == OFF) { // inherited::handleEvent( action ); // return; //} // // If this is a mouseMotion event, then check for locate highlighting // if (event->isOfType(SoLocation2Event::getClassTypeId())) { // check to see if the mouse is over our geometry... SbBool underTheMouse = FALSE; const SoPickedPoint * pp = this->getPickedPoint(action); SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL; if (pPath && pPath->containsPath(action->getCurPath())) { // Make sure I'm the lowest LocHL in the pick path! underTheMouse = TRUE; for (int i = 0; i < pPath->getLength(); i++) { SoNode *node = pPath->getNodeFromTail(i); if (node->isOfType(SoFCSelection::getClassTypeId())) { if (node != this) underTheMouse = FALSE; break; // found the lowest LocHL - look no further } } } // Am I currently highlighted? if (isHighlighted(action)) { if (! underTheMouse) { // re-draw the object with it's normal color //if(mymode != OFF) redrawHighlighted(action, FALSE); Gui::Selection().rmvPreselect(); } else { action->setHandled(); //const SoPickedPoint * pp = action->getPickedPoint(); Gui::Selection().setPreselectCoord(pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); } } // Else I am not currently highlighted else { // If under the mouse, then highlight! if (underTheMouse) { // draw this object highlighted if (mymode != OFF) redrawHighlighted(action, TRUE); //const SoPickedPoint * pp = action->getPickedPoint(); Gui::Selection().setPreselect(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); } } //if(selected == SELECTED){ // redrawHighlighted(action, TRUE); //} //if(selectionCleared ){ // redrawHighlighted(action, FALSE); // selectionCleared = false; //} } // key press events else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) { SoKeyboardEvent * const e = (SoKeyboardEvent *) event; if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT) || SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT) ) bShift = true; if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT) || SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT) ) bShift = false; if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL) || SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL) ) bCtrl = true; if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) || SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) ) bCtrl = false; } // mouse press events for (de)selection (only if selection is enabled on this node) else if (event->isOfType(SoMouseButtonEvent::getClassTypeId()) && selectionMode.getValue() == SoFCSelection::SEL_ON) { SoMouseButtonEvent * const e = (SoMouseButtonEvent *) event; if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) { //FIXME: Shouldn't we remove the preselection for newly selected objects? // Otherwise the tree signals that an object is preselected even though it is hidden. (Werner) const SoPickedPoint * pp = this->getPickedPoint(action); if (pp && pp->getPath()->containsPath(action->getCurPath())) { if (bCtrl) { if (Gui::Selection().isSelected(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString())) { Gui::Selection().rmvSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString()); } else { Gui::Selection().addSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); if (mymode == OFF) { snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); getMainWindow()->statusBar()->showMessage(QString::fromAscii(buf),3000); } } } else { // Ctrl if (!Gui::Selection().isSelected(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString())) { Gui::Selection().clearSelection(documentName.getValue().getString()); Gui::Selection().addSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); } else { Gui::Selection().clearSelection(documentName.getValue().getString()); Gui::Selection().addSelection(documentName.getValue().getString() ,objectName.getValue().getString() ,0 ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); } if (mymode == OFF) { snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString() ,objectName.getValue().getString() ,subElementName.getValue().getString() ,pp->getPoint()[0] ,pp->getPoint()[1] ,pp->getPoint()[2]); getMainWindow()->statusBar()->showMessage(QString::fromAscii(buf),3000); } } action->setHandled(); } // picked point } // mouse release } // Let the base class traverse the children. if (action->getGrabber() != this) inherited::handleEvent(action); #endif }
void SoLineHighlightRenderActionP::drawBoxes(SoPath * pathtothis, const SoPathList * pathlist) { int i; int thispos = reclassify_cast<SoFullPath *>(pathtothis)->getLength()-1; assert(thispos >= 0); this->postprocpath->setHead(pathtothis->getHead()); // reset for (i = 1; i < thispos; i++) { this->postprocpath->append(pathtothis->getIndex(i)); } SoState * state = PUBLIC(this)->getState(); state->push(); // we need to disable accumulation buffer antialiasing while // rendering selected objects int oldnumpasses = PUBLIC(this)->getNumPasses(); PUBLIC(this)->setNumPasses(1); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); SoColorPacker ** cptr = static_cast<SoColorPacker **>(this->colorpacker_storage.get()); SoLazyElement::setDiffuse(state, pathtothis->getHead(), 1, &this->color, *cptr); // FIXME: we should check this versus the actual max line width // supported by the underlying OpenGL context. 20050610 mortene. SoLineWidthElement::set(state, this->linewidth); SoLinePatternElement::set(state, this->linepattern); SoTextureQualityElement::set(state, 0.0f); SoDrawStyleElement::set(state, SoDrawStyleElement::LINES); SoPolygonOffsetElement::set(state, NULL, -1.0f, -1.0f, SoPolygonOffsetElement::LINES, TRUE); SoMaterialBindingElement::set(state, NULL, SoMaterialBindingElement::OVERALL); SoNormalElement::set(state, NULL, 0, NULL, FALSE); SoOverrideElement::setNormalVectorOverride(state, NULL, TRUE); SoOverrideElement::setMaterialBindingOverride(state, NULL, TRUE); SoOverrideElement::setLightModelOverride(state, NULL, TRUE); SoOverrideElement::setDiffuseColorOverride(state, NULL, TRUE); SoOverrideElement::setLineWidthOverride(state, NULL, TRUE); SoOverrideElement::setLinePatternOverride(state, NULL, TRUE); SoOverrideElement::setDrawStyleOverride(state, NULL, TRUE); SoOverrideElement::setPolygonOffsetOverride(state, NULL, TRUE); SoTextureOverrideElement::setQualityOverride(state, TRUE); for (i = 0; i < pathlist->getLength(); i++) { SoFullPath * path = reclassify_cast<SoFullPath *>((*pathlist)[i]); this->postprocpath->append(path->getHead()); for (int j = 1; j < path->getLength(); j++) { this->postprocpath->append(path->getIndex(j)); } PUBLIC(this)->SoGLRenderAction::apply(this->postprocpath); this->postprocpath->truncate(thispos); } PUBLIC(this)->setNumPasses(oldnumpasses); state->pop(); }
void Scene::load(const ::std::string& filename, const bool& doBoundingBoxPoints, const bool& doPoints) { ::rl::xml::DomParser parser; ::rl::xml::Document doc = parser.readFile(filename, "", XML_PARSE_NOENT | XML_PARSE_XINCLUDE); doc.substitute(XML_PARSE_NOENT | XML_PARSE_XINCLUDE); ::rl::xml::Path path(doc); ::rl::xml::Object scenes = path.eval("//scene"); for (int i = 0; i < ::std::min(1, scenes.getNodeNr()); ++i) { SoInput input; if (!input.openFile(scenes.getNodeTab(i).getLocalPath(scenes.getNodeTab(i).getAttribute("href").getValue()).c_str() ,true)) { throw Exception("::rl::sg::Scene::load() - failed to open file"); } SoVRMLGroup* root = SoDB::readAllVRML(&input); if (NULL == root) { throw Exception("::rl::sg::Scene::load() - failed to read file"); } SbViewportRegion viewportRegion; root->ref(); // model ::rl::xml::Object models = path.eval("model", scenes.getNodeTab(i)); for (int j = 0; j < models.getNodeNr(); ++j) { SoSearchAction modelSearchAction; modelSearchAction.setName(models.getNodeTab(j).getAttribute("name").getValue().c_str()); modelSearchAction.apply(root); if (NULL == modelSearchAction.getPath()) { continue; } Model* model = this->create(); model->setName(models.getNodeTab(j).getAttribute("name").getValue()); // body ::rl::xml::Object bodies = path.eval("body", models.getNodeTab(j)); for (int k = 0; k < bodies.getNodeNr(); ++k) { SoSearchAction bodySearchAction; bodySearchAction.setName(bodies.getNodeTab(k).getAttribute("name").getValue().c_str()); bodySearchAction.apply(static_cast< SoFullPath* >(modelSearchAction.getPath())->getTail()); if (NULL == bodySearchAction.getPath()) { continue; } Body* body = model->create(); body->setName(bodies.getNodeTab(k).getAttribute("name").getValue()); SoSearchAction pathSearchAction; pathSearchAction.setNode(static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail()); pathSearchAction.apply(root); SoGetMatrixAction bodyGetMatrixAction(viewportRegion); bodyGetMatrixAction.apply(static_cast< SoFullPath* >(pathSearchAction.getPath())); SbMatrix bodyMatrix = bodyGetMatrixAction.getMatrix(); if (!this->isScalingSupported) { SbVec3f bodyTranslation; SbRotation bodyRotation; SbVec3f bodyScaleFactor; SbRotation bodyScaleOrientation; SbVec3f bodyCenter; bodyMatrix.getTransform(bodyTranslation, bodyRotation, bodyScaleFactor, bodyScaleOrientation, bodyCenter); for (int l = 0; l < 3; ++l) { if (::std::abs(bodyScaleFactor[l] - 1.0f) > 1.0e-6f) { throw Exception("::rl::sg::Scene::load() - bodyScaleFactor not supported"); } } } ::rl::math::Transform frame; for (int m = 0; m < 4; ++m) { for (int n = 0; n < 4; ++n) { frame(m, n) = bodyMatrix[n][m]; } } body->setFrame(frame); if (static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail()->isOfType(SoVRMLTransform::getClassTypeId())) { SoVRMLTransform* bodyVrmlTransform = static_cast< SoVRMLTransform* >(static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail()); for (int l = 0; l < 3; ++l) { body->center(l) = bodyVrmlTransform->center.getValue()[l]; } } SoPathList pathList; // shape SoSearchAction shapeSearchAction; shapeSearchAction.setInterest(SoSearchAction::ALL); shapeSearchAction.setType(SoVRMLShape::getClassTypeId()); shapeSearchAction.apply(static_cast< SoFullPath* >(bodySearchAction.getPath())->getTail()); for (int l = 0; l < shapeSearchAction.getPaths().getLength(); ++l) { SoFullPath* path = static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l]); if (path->getLength() > 1) { path = static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l]->copy(1, static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l])->getLength() - 1)); } pathList.append(path); SoGetMatrixAction shapeGetMatrixAction(viewportRegion); shapeGetMatrixAction.apply(path); SbMatrix shapeMatrix = shapeGetMatrixAction.getMatrix(); if (!this->isScalingSupported) { SbVec3f shapeTranslation; SbRotation shapeRotation; SbVec3f shapeScaleFactor; SbRotation shapeScaleOrientation; SbVec3f shapeCenter; shapeMatrix.getTransform(shapeTranslation, shapeRotation, shapeScaleFactor, shapeScaleOrientation, shapeCenter); for (int m = 0; m < 3; ++m) { if (::std::abs(shapeScaleFactor[m] - 1.0f) > 1.0e-6f) { throw Exception("::rl::sg::Scene::load() - shapeScaleFactor not supported"); } } } SoVRMLShape* shapeVrmlShape = static_cast< SoVRMLShape* >(static_cast< SoFullPath* >(shapeSearchAction.getPaths()[l])->getTail()); Shape* shape = body->create(shapeVrmlShape); shape->setName(shapeVrmlShape->getName().getString()); ::rl::math::Transform transform; for (int m = 0; m < 4; ++m) { for (int n = 0; n < 4; ++n) { transform(m, n) = shapeMatrix[n][m]; } } shape->setTransform(transform); } // bounding box if (doBoundingBoxPoints) { SoGetBoundingBoxAction getBoundingBoxAction(viewportRegion); getBoundingBoxAction.apply(pathList); SbBox3f boundingBox = getBoundingBoxAction.getBoundingBox(); for (int l = 0; l < 3; ++l) { body->max(l) = boundingBox.getMax()[l]; body->min(l) = boundingBox.getMin()[l]; } } // convex hull if (doPoints) { SoCallbackAction callbackAction; callbackAction.addTriangleCallback(SoVRMLGeometry::getClassTypeId(), Scene::triangleCallback, &body->points); callbackAction.apply(pathList); } } } root->unref(); } }
////////////////////////////////////////////////////////////////////////////// // // beginTraversal - have the base class render the passed scene graph, // then render highlights for our selection node. // void SoBoxHighlightRenderAction::apply(SoNode *renderRoot) // ////////////////////////////////////////////////////////////////////////////// { // Render the scene SoGLRenderAction::apply(renderRoot); // Render the highlight? if (! hlVisible) return; // Is our cached path still valid? if ((selPath == NULL) || (selPath->getHead() != renderRoot) || (! selPath->getTail()->isOfType(SoSelection::getClassTypeId()))) { // Find the selection node under the render root static SoSearchAction *sa1 = NULL; if (sa1 == NULL) sa1 = new SoSearchAction; else sa1->reset(); sa1->setFind(SoSearchAction::TYPE); sa1->setInterest(SoSearchAction::FIRST); sa1->setType(SoSelection::getClassTypeId()); sa1->apply(renderRoot); // Cache this path if (selPath != NULL) selPath->unref(); selPath = sa1->getPath(); if (selPath != NULL) { selPath = selPath->copy(); selPath->ref(); } } if (selPath != NULL) { // Make sure something is selected SoSelection *sel = (SoSelection *) selPath->getTail(); if (sel->getNumSelected() == 0) return; // Keep the length from the root to the selection // as an optimization so we can reuse this data int reusablePathLength = selPath->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 { selPath->append(fp->getIndex(++k)); } while ( fp->getNode(k) != kitTail ); } else { for (int k = 1; k < p->getLength(); k++) selPath->append(p->getIndex(k)); } // Find the camera used to render the selected object and // insert it into the highlight graph as the first child SoNode *camera; static SoSearchAction *sa2 = NULL; if (sa2 == NULL) sa2 = new SoSearchAction; else sa2->reset(); sa2->setFind(SoSearchAction::TYPE); sa2->setInterest(SoSearchAction::LAST); sa2->setType(SoCamera::getClassTypeId()); sa2->apply(selPath); camera =(sa2->getPath() == NULL ? NULL : sa2->getPath()->getTail()); if (camera != NULL) localRoot->insertChild(camera, 0); // Get the bounding box of the object and update the // local highlight graph updateBbox(selPath); // Make sure the box has some size if ((cube->width.getValue() == 0) && (cube->height.getValue() == 0) && (cube->depth.getValue() == 0)) { #ifdef DEBUG SoDebugError::postWarning("SoBoxHighlightRenderAction::apply", "selected object has no bounding box - no highlight rendered"); #endif } else { // Render the highlight SoGLRenderAction::apply(localRoot); } // Restore selPath for reuse selPath->truncate(reusablePathLength); // Remove the camera for the next path if (camera != NULL) localRoot->removeChild(0); } } }