void SoXipGetCameraProperties::GLRender(SoGLRenderAction* action) { /* SbMatrix mMV = SoModelMatrixElement::get(action->getState()) * SoViewingMatrixElement::get(action->getState()); SbMatrix mv = mMV.transpose(); mv = mv.inverse(); SbVec3f cc(0.0,0.0,0.0); SbVec3f wc; mv.multMatrixVec(cc, wc); */ SbViewVolume vv = SoViewVolumeElement::get( action->getState() ); mCamPos = vv.getSightPoint(0.0); if (mCamPos != camPos.getValue()) camPos.setValue( mCamPos ); mCamDir = vv.getSightPoint(1.0) - vv.getSightPoint(0.0); if (mCamDir != camDir.getValue() ) camDir.setValue( mCamDir ); SbViewportRegion vpr = SoViewportRegionElement::get( action->getState() ); SbVec2s orig = vpr.getViewportOriginPixels(); SbVec2s wh = vpr.getViewportSizePixels(); SbVec4f vp = SbVec4f( (float)orig[0], (float)orig[1], (float)wh[0], (float)wh[1] ); mViewport = vp; if (mViewport != viewport.getValue()) viewport.setValue( mViewport ); }
float SoZoomTranslation::getScaleFactor(SoAction* action) const { // Dividing by 5 seems to work well SbViewVolume vv = SoViewVolumeElement::get(action->getState()); float aspectRatio = SoViewportRegionElement::get(action->getState()).getViewportAspectRatio(); float scale = vv.getWorldToScreenScale(SbVec3f(0.f, 0.f, 0.f), 0.1f) / (5*aspectRatio); return scale; }
void ViewProviderStructured::cut(const std::vector<SbVec2f>& picked, Gui::View3DInventorViewer &Viewer) { // create the polygon from the picked points Base::Polygon2D cPoly; for (std::vector<SbVec2f>::const_iterator it = picked.begin(); it != picked.end(); ++it) { cPoly.Add(Base::Vector2D((*it)[0],(*it)[1])); } // get a reference to the point feature Points::Feature* fea = static_cast<Points::Feature*>(pcObject); const Points::PointKernel& points = fea->Points.getValue(); SoCamera* pCam = Viewer.getSoRenderManager()->getCamera(); SbViewVolume vol = pCam->getViewVolume(); // search for all points inside/outside the polygon Points::PointKernel newKernel; newKernel.reserve(points.size()); bool invalidatePoints = false; double nan = std::numeric_limits<double>::quiet_NaN(); for (Points::PointKernel::const_iterator jt = points.begin(); jt != points.end(); ++jt) { // valid point? Base::Vector3d vec(*jt); if (!(boost::math::isnan(jt->x) || boost::math::isnan(jt->y) || boost::math::isnan(jt->z))) { SbVec3f pt(jt->x,jt->y,jt->z); // project from 3d to 2d vol.projectToScreen(pt, pt); if (cPoly.Contains(Base::Vector2D(pt[0],pt[1]))) { invalidatePoints = true; vec.Set(nan, nan, nan); } } newKernel.push_back(vec); } if (invalidatePoints) { //Remove the points from the cloud and open a transaction object for the undo/redo stuff Gui::Application::Instance->activeDocument()->openCommand("Cut points"); // sets the points outside the polygon to update the Inventor node fea->Points.setValue(newKernel); // unset the modified flag because we don't need the features' execute() to be called Gui::Application::Instance->activeDocument()->commitCommand(); fea->purgeTouched(); } }
// Doc in superclass. SbViewVolume SoOrthographicCamera::getViewVolume(float useaspectratio) const { SbViewVolume volume; if (useaspectratio == 0.0f) useaspectratio = this->aspectRatio.getValue(); float halfheight = this->height.getValue() * 0.5f; float halfwidth = halfheight * useaspectratio; volume.ortho(-halfwidth, halfwidth, -halfheight, halfheight, this->nearDistance.getValue(), this->farDistance.getValue()); volume.rotateCamera(this->orientation.getValue()); volume.translateCamera(this->position.getValue()); return volume; }
void SoXipMarkerSet::GLRender( SoGLRenderAction* action ) { if (mCoord && mFaceSet && mScale && mTranslation && mRotation) { float pointSize = SoPointSizeElement::get(action->getState()); SbViewportRegion vp = SoViewportRegionElement::get(action->getState()); SbViewVolume vVol = SoViewVolumeElement::get(action->getState()); // world to pixel scale float scaleFactorY = pointSize * vVol.getHeight() / (float) vp.getViewportSizePixels()[1]; float scaleFactorX = pointSize * vVol.getWidth() / (float) vp.getViewportSizePixels()[0]; mScale->scaleFactor.setValue(0.5f * scaleFactorX, 0.5f * scaleFactorY, 1); // world to screen rotation SbMatrix affine, proj; vVol.getMatrices(affine, proj); SbVec3f t, s; SbRotation rot, so; affine.inverse().getTransform(t, rot, s, so); mRotation->rotation.setValue(rot); // number of coordinates const SoCoordinateElement *ce = (const SoCoordinateElement *) SoCoordinateElement::getInstance(action->getState()); int numPts = 0; if (ce) { numPts = ce->getNum(); } SbXipMarkerShapes::getVertices(marker.getValue(), mCoord->point); SbXipMarkerShapes::getNumVertices(marker.getValue(), mFaceSet->numVertices); for (int i = 0; i < numPts; i++) { mTranslation->translation.setValue(ce->get3(i)); action->getState()->push(); action->traverse(mTranslation); action->traverse(mRotation); action->traverse(mScale); action->traverse(mCoord); action->traverse(mFaceSet); action->getState()->pop(); } } }
void SoFCCSysDragger::idleCB(void *data, SoSensor *) { SoFCCSysDragger *sudoThis = reinterpret_cast<SoFCCSysDragger *>(data); assert(sudoThis->camera); SbMatrix localToWorld = sudoThis->getLocalToWorldMatrix(); SbVec3f origin; localToWorld.multVecMatrix(SbVec3f(0.0, 0.0, 0.0), origin); SbViewVolume viewVolume = sudoThis->camera->getViewVolume(); float radius = sudoThis->draggerSize.getValue() / 2.0; float localScale = viewVolume.getWorldToScreenScale(origin, radius); SbVec3f scaleVector(localScale, localScale, localScale); SoScale *localScaleNode = SO_GET_ANY_PART(sudoThis, "scaleNode", SoScale); localScaleNode->scaleFactor.setValue(scaleVector); sudoThis->autoScaleResult.setValue(localScale); }
void ViewProviderPoints::cut(const std::vector<SbVec2f>& picked, Gui::View3DInventorViewer &Viewer) { // create the polygon from the picked points Base::Polygon2D cPoly; for (std::vector<SbVec2f>::const_iterator it = picked.begin(); it != picked.end(); ++it) { cPoly.Add(Base::Vector2D((*it)[0],(*it)[1])); } // get a reference to the point feature Points::Feature* fea = (Points::Feature*)pcObject; const Points::PointKernel& points = fea->Points.getValue(); SoCamera* pCam = Viewer.getSoRenderManager()->getCamera(); SbViewVolume vol = pCam->getViewVolume(); // search for all points inside/outside the polygon Points::PointKernel newKernel; for ( Points::PointKernel::const_iterator jt = points.begin(); jt != points.end(); ++jt ) { SbVec3f pt(jt->x,jt->y,jt->z); // project from 3d to 2d vol.projectToScreen(pt, pt); if (!cPoly.Contains(Base::Vector2D(pt[0],pt[1]))) newKernel.push_back(*jt); } if (newKernel.size() == points.size()) return; // nothing needs to be done //Remove the points from the cloud and open a transaction object for the undo/redo stuff Gui::Application::Instance->activeDocument()->openCommand("Cut points"); // sets the points outside the polygon to update the Inventor node fea->Points.setValue(newKernel); // unset the modified flag because we don't need the features' execute() to be called Gui::Application::Instance->activeDocument()->commitCommand(); fea->purgeTouched(); }
void getScreenPixelVectors(SoGLRenderAction *action, const SbVec3f position, SbVec3f &xPixelVec, SbVec3f &yPixelVec) { // To compute correct offset in world space we project width of text onto a plane parallel // to the near plane of the camera that goes through the current translation of the model matrix. SoState *state = action->getState(); SbPlaneProjector planeProj(FALSE); SbViewVolume viewVolume = SoViewVolumeElement::get(state); SbViewportRegion viewport = SoViewportRegionElement::get(state); planeProj.setViewVolume(viewVolume); planeProj.setPlane(SbPlane(viewVolume.getPlane(0.f).getNormal(), position)); float pixelWidth = 1.f / (float) viewport.getViewportSizePixels()[0]; float pixelHeight = 1.f / (float) viewport.getViewportSizePixels()[1]; SbVec3f p1 = planeProj.project(SbVec2f(0, 0)); SbVec3f p2 = planeProj.project(SbVec2f(pixelWidth, 0)); xPixelVec = (p2 - p1); p2 = planeProj.project(SbVec2f(0, pixelHeight)); yPixelVec = (p2 - p1); }
void GLFlagWindow::paintGL() { // draw lines for the flags if (_flagLayout) { // it can happen that the GL widget gets replaced internally (SoQt only, not with quarter) which // causes to destroy the FlagLayout instance int ct = _flagLayout->count(); const SbViewportRegion vp = _viewer->getSoRenderManager()->getViewportRegion(); SbVec2s size = vp.getViewportSizePixels(); float aspectratio = float(size[0])/float(size[1]); SbViewVolume vv = _viewer->getSoRenderManager()->getCamera()->getViewVolume(aspectratio); for (int i=0; i<ct;i++) { Flag* flag = qobject_cast<Flag*>(_flagLayout->itemAt(i)->widget()); if (flag) { SbVec3f pt = flag->getOrigin(); vv.projectToScreen(pt, pt); int tox = (int)(pt[0] * size[0]); int toy = (int)((1.0f-pt[1]) * size[1]); flag->drawLine(_viewer, tox, toy); } } } }
// doc from superclass. void SoNurbsProfile::getVertices(SoState * state, int32_t & numvertices, SbVec2f * & vertices) { // FIXME: optimize by detecting when the previously calculated // vertices can be returned. pederb, 20000922 int32_t numpoints; float * points; int floatspervec; int32_t numknots; float * knotvector; this->getTrimCurve(state, numpoints, points, floatspervec, numknots, knotvector); if (numpoints == 0 || numknots == 0) { numvertices = 0; vertices = NULL; return; } SbList <float> * coordListNurbsProfile = so_nurbsprofile_get_coordlist(FALSE); SbList <float> * nurbsProfileTempList = so_nurbsprofile_get_coordlist(TRUE); nurbsProfileTempList->truncate(0); for (int i = 0; i < numpoints; i++) { nurbsProfileTempList->append(points[i*floatspervec]); nurbsProfileTempList->append(points[i*floatspervec+1]); if (GLUWrapper()->available && GLUWrapper()->versionMatchesAtLeast(1, 3, 0)) { nurbsProfileTempList->append(0.0f); // gluNurbs needs 3D coordinates } } if (GLUWrapper()->available && GLUWrapper()->versionMatchesAtLeast(1, 3, 0)) { // we will write into this array in the GLU callback coordListNurbsProfile->truncate(0); if (this->nurbsrenderer == NULL) { this->nurbsrenderer = GLUWrapper()->gluNewNurbsRenderer(); GLUWrapper()->gluNurbsCallback(this->nurbsrenderer, (GLenum) GLU_NURBS_VERTEX, (gluNurbsCallback_cb_t)nurbsprofile_tess_vertex); GLUWrapper()->gluNurbsProperty(this->nurbsrenderer, (GLenum) GLU_NURBS_MODE, GLU_NURBS_TESSELLATOR); GLUWrapper()->gluNurbsProperty(this->nurbsrenderer, (GLenum) GLU_AUTO_LOAD_MATRIX, FALSE); GLUWrapper()->gluNurbsProperty(this->nurbsrenderer, (GLenum) GLU_DISPLAY_MODE, GLU_POINT); GLUWrapper()->gluNurbsProperty(this->nurbsrenderer, (GLenum) GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE); } // this looks pretty good float cmplx = SoComplexityElement::get(state); cmplx += 1.0f; cmplx = cmplx * cmplx * cmplx; GLUWrapper()->gluNurbsProperty(this->nurbsrenderer, (GLenum) GLU_U_STEP, float(numpoints)*cmplx); // these values are not important as we're not using screen-space // complexity (yet) SbMatrix modelmatrix = SbMatrix::identity(); SbMatrix affine, proj; SbViewVolume vv; vv.ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); vv.getMatrices(affine, proj); GLint viewport[4]; viewport[0] = 0; viewport[1] = 0; viewport[2] = 256; viewport[3] = 256; GLUWrapper()->gluLoadSamplingMatrices(this->nurbsrenderer, modelmatrix[0], proj[0], viewport); // generate curve GLUWrapper()->gluBeginCurve(this->nurbsrenderer); GLUWrapper()->gluNurbsCurve(this->nurbsrenderer, numknots, (float*)knotvector, 3, (float*)nurbsProfileTempList->getArrayPtr(), numknots - numpoints, GL_MAP1_VERTEX_3); GLUWrapper()->gluEndCurve(this->nurbsrenderer); // when we get here, the GLU callback should have added the // points to the list numvertices = coordListNurbsProfile->getLength() / 2; vertices = (SbVec2f*) coordListNurbsProfile->getArrayPtr(); } else { // just send the control points when GLU v1.3 is not available numvertices = numpoints; vertices = (SbVec2f*) nurbsProfileTempList->getArrayPtr(); } }
void ViewProviderScattered::cut(const std::vector<SbVec2f>& picked, Gui::View3DInventorViewer &Viewer) { // create the polygon from the picked points Base::Polygon2D cPoly; for (std::vector<SbVec2f>::const_iterator it = picked.begin(); it != picked.end(); ++it) { cPoly.Add(Base::Vector2D((*it)[0],(*it)[1])); } // get a reference to the point feature Points::Feature* fea = static_cast<Points::Feature*>(pcObject); const Points::PointKernel& points = fea->Points.getValue(); SoCamera* pCam = Viewer.getSoRenderManager()->getCamera(); SbViewVolume vol = pCam->getViewVolume(); // search for all points inside/outside the polygon std::vector<unsigned long> removeIndices; removeIndices.reserve(points.size()); unsigned long index = 0; for (Points::PointKernel::const_iterator jt = points.begin(); jt != points.end(); ++jt, ++index) { SbVec3f pt(jt->x,jt->y,jt->z); // project from 3d to 2d vol.projectToScreen(pt, pt); if (cPoly.Contains(Base::Vector2D(pt[0],pt[1]))) removeIndices.push_back(index); } if (removeIndices.empty()) return; // nothing needs to be done //Remove the points from the cloud and open a transaction object for the undo/redo stuff Gui::Application::Instance->activeDocument()->openCommand("Cut points"); // sets the points outside the polygon to update the Inventor node fea->Points.removeIndices(removeIndices); std::map<std::string,App::Property*> Map; pcObject->getPropertyMap(Map); for (std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it) { Base::Type type = it->second->getTypeId(); if (type == Points::PropertyNormalList::getClassTypeId()) { static_cast<Points::PropertyNormalList*>(it->second)->removeIndices(removeIndices); } else if (type == Points::PropertyGreyValueList::getClassTypeId()) { static_cast<Points::PropertyGreyValueList*>(it->second)->removeIndices(removeIndices); } else if (type == App::PropertyColorList::getClassTypeId()) { //static_cast<App::PropertyColorList*>(it->second)->removeIndices(removeIndices); const std::vector<App::Color>& colors = static_cast<App::PropertyColorList*>(it->second)->getValues(); if (removeIndices.size() > colors.size()) break; std::vector<App::Color> remainValue; remainValue.reserve(colors.size() - removeIndices.size()); std::vector<unsigned long>::iterator pos = removeIndices.begin(); for (std::vector<App::Color>::const_iterator jt = colors.begin(); jt != colors.end(); ++jt) { unsigned long index = jt - colors.begin(); if (pos == removeIndices.end()) remainValue.push_back( *jt ); else if (index != *pos) remainValue.push_back( *jt ); else ++pos; } static_cast<App::PropertyColorList*>(it->second)->setValues(remainValue); } } // unset the modified flag because we don't need the features' execute() to be called Gui::Application::Instance->activeDocument()->commitCommand(); fea->purgeTouched(); }
void SmTextureText2::renderString(const SmTextureFontBundle & bundle, const SbString * s, const int numstring, const SbVec3f & pos, const SbViewVolume & vv, const SbViewportRegion & vp, const SbMatrix & projmatrix, const SbMatrix & modelmatrix, const SbMatrix & invmodelmatrix, const float rotation) { // get distance from pos to camera plane SbVec3f tmp; modelmatrix.multVecMatrix(pos, tmp); float dist = -vv.getPlane(0.0f).getDistance(tmp); if (dist <= vv.getNearDist()) return; if (dist > (vv.getNearDist() + vv.getDepth())) return; float maxr = this->maxRange.getValue(); if (maxr > 0.0f && dist > maxr) return; int i; SbVec2s vpsize = vp.getViewportSizePixels(); SbVec3f screenpoint; projmatrix.multVecMatrix(pos, screenpoint); int xmin = 0; int ymax = bundle.getAscent(); int ymin = ymax - numstring * (bundle.height() + bundle.getLeading()); ymin += bundle.getLeading(); short h = ymax - ymin; short halfh = h / 2; switch (this->verticalJustification.getValue()) { case SmTextureText2::BOTTOM: break; case SmTextureText2::TOP: ymin -= bundle.getAscent(); ymax -= bundle.getAscent(); break; case SmTextureText2::VCENTER: ymin -= halfh; ymax -= halfh; break; default: assert(0 && "unknown alignment"); break; } SbList <int> widthlist; for (i = 0; i < numstring; i++) { widthlist.append(bundle.stringWidth(s[i])); } for (i = 0; i < numstring; i++) { int len = s[i].getLength(); if (len == 0) continue; SbVec2s sp; if (!get_screenpoint_pixels(screenpoint, vpsize, sp)) continue; SbVec2s n0 = SbVec2s(sp[0] + xmin, sp[1] + ymax - (i+1)*bundle.height()); short w = static_cast<short>(widthlist[i]); short halfw = w / 2; switch (this->justification.getValue()) { case SmTextureText2::LEFT: break; case SmTextureText2::RIGHT: n0[0] -= w; break; case SmTextureText2::CENTER: n0[0] -= halfw; break; default: assert(0 && "unknown alignment"); break; } if (rotation != 0) { float x = static_cast<float>(sp[0]); float y = static_cast<float>(sp[1]); glPushMatrix(); glTranslatef(x, y, 0); glRotatef(rotation * static_cast<float>(180 / M_PI), 0, 0, 1); glTranslatef(-x, -y, 0); } bundle.begin(); bundle.renderString(s[i], SbVec3f(n0[0], n0[1], screenpoint[2])); bundle.end(); if (rotation != 0) glPopMatrix(); } }
//====================================================================== // // Description: // projection of telepointer // // // Use: private //====================================================================== void TPHandler::projectTelePointer(TelePointer *, const SbVec3f pos, float aspectRatio, SbVec3f &intersection, InvExaminerViewer *viewer) { const int xOffset = 61; const int yOffset = 33; float xs, ys, zs; // normalized screen coordinates SbVec3f screen; SbVec2s size = viewer->getSize(); if (viewer->isDecoration()) { // !! Attention: SoXtRenderArea with offset size[0] = size[0] - xOffset; size[1] = size[1] - yOffset; } float aspRat = size[0] / (float)size[1]; // set aspect ratio explicitely tp_camera->aspectRatio.setValue(aspRat); // default setting tp_camera->height.setValue(2.0); // scale height tp_camera->scaleHeight(1 / aspRat); /* float h = tp_camera->height.getValue(); fprintf(stderr, "Height Camera: %.6f\n", h); */ // get the view volume -> rectangular box SbViewVolume viewVolume = tp_camera->getViewVolume(); // determine mouse position viewVolume.projectToScreen(pos, screen); screen.getValue(xs, ys, zs); /* cerr << "xs: " << xs << endl; cerr << "ys: " << ys << endl; */ // project the mouse point to a line SbVec3f p0, p1; viewVolume.projectPointToLine(SbVec2f(xs, ys), p0, p1); // take the midpoint of the line as telepointer position intersection = (p0 + p1) / 2.0f; // adapt telepointer position to the aspect ratio if (aspectRatio > 1.0) { intersection[0] = intersection[0] * aspectRatio / aspRat; intersection[1] = intersection[1] * aspectRatio / aspRat; } if (aspectRatio < 1.0) { // in this case the aspect ratio submitted to the function // and belonging to the delivered position leads to wrong projection point // => local correction for x-, y-value intersection[0] = intersection[0] / aspRat; intersection[1] = intersection[1] / aspRat; } /* float fx,fy,fz; intersection.getValue(fx,fy,fz); cerr << "TP: (" << fx << "," << fy << "," << fz << ")" << endl; */ }
void SoXipCPUMprRender::GLRender(SoGLRenderAction * action) { SoState *state = action->getState(); SbViewportRegion vpRegion = SoViewportRegionElement::get(state); SbVec2s vpSize = vpRegion.getViewportSizePixels(); // Don't do anything if 0 size if (!vpSize[0] || !vpSize[1]) return; // Bind texture to available texture stage if (!mMPRTexId) glGenTextures(1, &mMPRTexId); int texUnit = SoXipMultiTextureElement::getFreeUnit(state); SoXipMultiTextureElement::setUnit(state, texUnit); SoXipMultiTextureElement::bindTexture(state, GL_TEXTURE_2D, mMPRTexId); // Check the size against min/max SbVec2s minmax = minMaxSize.getValue(); int which = (vpSize[0] > vpSize[1]) ? 0 : 1; float ratio = (float) vpSize[which] / (float) vpSize[1 - which]; // If smallest dim is < min if (vpSize[1 - which] < minmax[0]) { // Clamp to min and change biggest dim according to aspect ratio vpSize[1 - which] = minmax[0]; vpSize[which] = (short) (ratio * vpSize[1 - which]); } // If biggest dim is > max if (vpSize[which] > minmax[1]) { // Clamp to max and change smallest dim according to aspect ratio vpSize[which] = minmax[1]; vpSize[1 - which] = (short) (vpSize[which] / ratio); } // Ready the buffers readyBuffers(state); if (vpSize[0] == 0 || vpSize[1] == 0) return; // Check if mpr texture must be resized if (mMPRSize != vpSize) { resizeBuffers(vpSize); mUpdateFlag |= UPDATE_MPRCACHE; } // Exit if unsupported image type if (mTexInternalFormat == 0 || mTexType == 0) return; // Check if orientation has changed SbVec3f corners[4]; SbViewVolume viewVolume = SoViewVolumeElement::get(state); float dist = viewVolume.getNearDist() + viewVolume.getDepth() * 0.5f; corners[0] = viewVolume.getPlanePoint(dist, SbVec2f(0, 1)); corners[1] = viewVolume.getPlanePoint(dist, SbVec2f(1, 1)); corners[2] = viewVolume.getPlanePoint(dist, SbVec2f(1, 0)); corners[3] = viewVolume.getPlanePoint(dist, SbVec2f(0, 0)); if (corners[0] != mCorners[0] || corners[1] != mCorners[1] || corners[2] != mCorners[2] || corners[3] != mCorners[3]) { mCorners[0] = corners[0]; mCorners[1] = corners[1]; mCorners[2] = corners[2]; mCorners[3] = corners[3]; mUpdateFlag |= UPDATE_MPRCACHE; } // if (mUpdateFlag & UPDATE_MPRCACHE) { // Compute new cache table and mpr switch (mVolDataType) { case SbXipImage::UNSIGNED_BYTE: mLutBuf ? computeMPRCacheLUT(this, (unsigned char*)mVolBuf, state) : computeMPRCache(this, (unsigned char*)mVolBuf, state); break; case SbXipImage::BYTE: mLutBuf ? computeMPRCacheLUT(this, (char*)mVolBuf, state) : computeMPRCache(this, (char*)mVolBuf, state); break; case SbXipImage::UNSIGNED_SHORT: mLutBuf ? computeMPRCacheLUT(this, (unsigned short*)mVolBuf, state) : computeMPRCache(this, (unsigned short*)mVolBuf, state); break; case SbXipImage::SHORT: mLutBuf ? computeMPRCacheLUT(this, (short*)mVolBuf, state) : computeMPRCache(this, (short*)mVolBuf, state); break; case SbXipImage::UNSIGNED_INT: mLutBuf ? computeMPRCacheLUT(this, (unsigned int*)mVolBuf, state) : computeMPRCache(this, (unsigned int*)mVolBuf, state); break; case SbXipImage::INT: mLutBuf ? computeMPRCacheLUT(this, (int*)mVolBuf, state) : computeMPRCache(this, (int*)mVolBuf, state); break; case SbXipImage::FLOAT: mLutBuf ? computeMPRCacheLUT(this, (float*)mVolBuf, state) : computeMPRCache(this, (float*)mVolBuf, state); break; case SbXipImage::DOUBLE: mLutBuf ? computeMPRCacheLUT(this, (double*)mVolBuf, state) : computeMPRCache(this, (double*)mVolBuf, state); break; default: // will never come here cause we already checked for it in resize break; } // Update mpr texture updateTexture(); } else if (mUpdateFlag & UPDATE_MPR) { // Compute new mpr switch (mVolDataType) { case SbXipImage::UNSIGNED_BYTE: mLutBuf ? computeMPRLUT(this, (unsigned char*)mVolBuf) : computeMPR(this, (unsigned char*)mVolBuf); break; case SbXipImage::BYTE: mLutBuf ? computeMPRLUT(this, (char*)mVolBuf) : computeMPR(this, (char*)mVolBuf); break; case SbXipImage::UNSIGNED_SHORT: mLutBuf ? computeMPRLUT(this, (unsigned short*)mVolBuf) : computeMPR(this, (unsigned short*)mVolBuf); break; case SbXipImage::SHORT: mLutBuf ? computeMPRLUT(this, (short*)mVolBuf) : computeMPR(this, (short*)mVolBuf); break; case SbXipImage::UNSIGNED_INT: mLutBuf ? computeMPRLUT(this, (unsigned int*)mVolBuf) : computeMPR(this, (unsigned int*)mVolBuf); break; case SbXipImage::INT: mLutBuf ? computeMPRLUT(this, (int*)mVolBuf) : computeMPR(this, (int*)mVolBuf); break; case SbXipImage::FLOAT: mLutBuf ? computeMPRLUT(this, (float*)mVolBuf) : computeMPR(this, (float*)mVolBuf); break; case SbXipImage::DOUBLE: mLutBuf ? computeMPRLUT(this, (double*)mVolBuf) : computeMPR(this, (double*)mVolBuf); break; default: // will never come here cause we already checked for it in resize break; } // Update mpr texture updateTexture(); } // Render mpr to a quad renderMPR(texUnit); // Reset update flag mUpdateFlag = 0; }
/** * Renders the label. */ void SoTextLabel::GLRender(SoGLRenderAction *action) { if (!this->shouldGLRender(action)) return; // only draw text without background if (!this->background.getValue()) { inherited::GLRender(action); return; } SoState * state = action->getState(); state->push(); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); SbBox3f box; SbVec3f center; this->computeBBox(action, box, center); if (!SoCullElement::cullTest(state, box, TRUE)) { SoMaterialBundle mb(action); mb.sendFirst(); const SbMatrix & mat = SoModelMatrixElement::get(state); //const SbViewVolume & vv = SoViewVolumeElement::get(state); const SbMatrix & projmatrix = (mat * SoViewingMatrixElement::get(state) * SoProjectionMatrixElement::get(state)); const SbViewportRegion & vp = SoViewportRegionElement::get(state); SbVec2s vpsize = vp.getViewportSizePixels(); // font stuff //float space = this->spacing.getValue(); //float fontsize = SoFontSizeElement::get(state); SbName fontname = SoFontNameElement::get(state); int lines = this->string.getNum(); // get left bottom corner of the label SbVec3f nilpoint(0.0f, 0.0f, 0.0f); projmatrix.multVecMatrix(nilpoint, nilpoint); nilpoint[0] = (nilpoint[0] + 1.0f) * 0.5f * vpsize[0]; nilpoint[1] = (nilpoint[1] + 1.0f) * 0.5f * vpsize[1]; #if 1 // Unfortunately, the size of the label is stored in the pimpl class of // SoText2 which cannot be accessed directly. However, there is a trick // to get the required information: set model, viewing and projection // matrix to the identity matrix and also view volume to some default // values. SoText2::computeBBox() then calls SoText2P::getQuad which // returns the sizes in form of the bounding box. These values can be // reverse-engineered to get width and height. state->push(); SoModelMatrixElement::set(state,this,SbMatrix::identity()); SoViewingMatrixElement::set(state,this,SbMatrix::identity()); SoProjectionMatrixElement::set(state,this,SbMatrix::identity()); SbViewVolume vv; vv.ortho(-1,1,-1,1,-1,1); SoViewVolumeElement::set(state,this,vv); SbBox3f box; SbVec3f center; this->computeBBox(action, box, center); state->pop(); float xmin,ymin,zmin,xmax,ymax,zmax; box.getBounds(xmin,ymin,zmin,xmax,ymax,zmax); SbVec3f v0(xmin,ymax,zmax); SbVec3f v1(xmax,ymax,zmax); SbVec3f v2(xmax,ymin,zmax); SbVec3f v3(xmin,ymin,zmax); vv.projectToScreen(v0,v0); vv.projectToScreen(v1,v1); vv.projectToScreen(v2,v2); vv.projectToScreen(v3,v3); float width,height; width = (v1[0]-v0[0])*vpsize[0]; height = (v1[1]-v3[1])*vpsize[1]; switch (this->justification.getValue()) { case SoText2::RIGHT: nilpoint[0] -= width; break; case SoText2::CENTER: nilpoint[0] -= 0.5f*width; break; default: break; } if (lines > 1) { nilpoint[1] -= (float(lines-1)/(float)lines*height); } #else // Unfortunately, the required size (in pixels) is stored in a non-accessible way // in the subclass SoText2. Thus, we try to get a satisfactory solution with Qt // methods. // The font name is of the form "family:style". If 'style' is given it can be // 'Bold', 'Italic' or 'Bold Italic'. QFont font; QString fn = QString::fromAscii(fontname.getString()); int pos = fn.indexOf(QLatin1Char(':')); if (pos > -1) { if (fn.indexOf(QLatin1String("Bold"),pos,Qt::CaseInsensitive) > pos) font.setBold(true); if (fn.indexOf(QLatin1String("Italic"),pos,Qt::CaseInsensitive) > pos) font.setItalic(true); fn = fn.left(pos); } font.setFamily(fn); font.setPixelSize((int)fontsize); QFontMetrics fm(font); float width = 0.0f; float height = 0.75f*fontsize*lines + (lines-1)*space;//fm.height(); float hh=0; for (int i = 0; i < lines; i++) { SbString str = this->string[i]; float w = fm.width(QLatin1String(this->string[i].getString())); width = std::max<float>(width, w); hh = fm.height(); } if (lines > 1) { nilpoint[1] -= ((lines-1)*fontsize*0.75f+space); } #endif SbVec3f toppoint = nilpoint; toppoint[0] += width; toppoint[1] += height; // Set new state. glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, vpsize[0], 0, vpsize[1], -1.0f, 1.0f); glPixelStorei(GL_UNPACK_ALIGNMENT,1); state->push(); // disable textures for all units SoGLTextureEnabledElement::set(state, this, FALSE); SoGLTexture3EnabledElement::set(state, this, FALSE); glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); // color and frame size SbColor color = this->backgroundColor.getValue(); float fs = this->frameSize.getValue(); // draw background glColor3f(color[0], color[1], color[2]); glBegin(GL_QUADS); glVertex3f(nilpoint[0]-fs,nilpoint[1]-fs,0.0f); glVertex3f(toppoint[0]+fs,nilpoint[1]-fs,0.0f); glVertex3f(toppoint[0]+fs,toppoint[1]+fs,0.0f); glVertex3f(nilpoint[0]-fs,toppoint[1]+fs,0.0f); glEnd(); // pop old state glPopClientAttrib(); glPopAttrib(); state->pop(); glPixelStorei(GL_UNPACK_ALIGNMENT,4); // Pop old GL matrix state. glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } state->pop(); inherited::GLRender(action); }
SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) { #if 0 // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } #else if (!this->isSeekMode() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene #endif const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getViewportRegion(); const SbVec2s size(vp.getViewportSizePixels()); const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); const SbVec2f posn((float) pos[0] / (float) SoQtMax((int)(size[0] - 1), 1), (float) pos[1] / (float) SoQtMax((int)(size[1] - 1), 1)); this->lastmouseposition = posn; // Set to TRUE if any event processing happened. Note that it is not // necessary to restrict ourselves to only do one "action" for an // event, we only need this flag to see if any processing happened // at all. SbBool processed = FALSE; const ViewerMode curmode = this->currentmode; ViewerMode newmode = curmode; // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. if (this->ctrldown != ev->wasCtrlDown()) { this->ctrldown = ev->wasCtrlDown(); } if (this->shiftdown != ev->wasShiftDown()) { this->shiftdown = ev->wasShiftDown(); } if (this->altdown != ev->wasAltDown()) { this->altdown = ev->wasAltDown(); } // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!processed && !viewer->isEditing()) { processed = handleEventInForeground(ev); if (processed) return TRUE; } // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; switch (event->getKey()) { case SoKeyboardEvent::LEFT_CONTROL: case SoKeyboardEvent::RIGHT_CONTROL: this->ctrldown = press; break; case SoKeyboardEvent::LEFT_SHIFT: case SoKeyboardEvent::RIGHT_SHIFT: this->shiftdown = press; break; case SoKeyboardEvent::LEFT_ALT: case SoKeyboardEvent::RIGHT_ALT: this->altdown = press; break; case SoKeyboardEvent::H: processed = TRUE; viewer->saveHomePosition(); break; case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: if (!this->isViewing()) this->setViewing(true); break; default: break; } } // Mouse Button / Spaceball Button handling if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; // SoDebugError::postInfo("processSoEvent", "button = %d", button); switch (button) { case SoMouseButtonEvent::BUTTON1: this->lockrecenter = TRUE; this->button1down = press; #if 0 // disable to avoid interferences where this key combination is used, too if (press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue()); this->lockrecenter = FALSE; } else if (!press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // is it just a left click? if (tmp.getValue() < dci && !this->lockrecenter) { if (!this->moveToPoint(pos)) { panToCenter(panningplane, posn); this->interactiveCountDec(); } processed = TRUE; } } else #endif if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = TRUE; } //else if (press && (this->currentmode == NavigationStyle::IDLE)) { // this->setViewing(true); // processed = TRUE; //} else if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; this->centerTime = ev->getTime(); processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; if (tmp.getValue() < dci) { newmode = NavigationStyle::ZOOMING; } processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { this->setViewing(false); processed = TRUE; } else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = TRUE; } break; case SoMouseButtonEvent::BUTTON2: // If we are in edit mode then simply ignore the RMB events // to pass the event to the base class. this->lockrecenter = TRUE; if (!viewer->isEditing()) { // If we are in zoom or pan mode ignore RMB events otherwise // the canvas doesn't get any release events if (this->currentmode != NavigationStyle::ZOOMING && this->currentmode != NavigationStyle::PANNING && this->currentmode != NavigationStyle::DRAGGING) { if (this->isPopupMenuEnabled()) { if (!press) { // release right mouse button this->openPopupMenu(event->getPosition()); } } } } // Alternative way of rotating & zooming if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; this->centerTime = ev->getTime(); processed = TRUE; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; if (tmp.getValue() < dci) { newmode = NavigationStyle::ZOOMING; } processed = TRUE; } this->button2down = press; break; case SoMouseButtonEvent::BUTTON3: if (press) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue()); this->lockrecenter = FALSE; } else { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // is it just a middle click? if (tmp.getValue() < dci && !this->lockrecenter) { if (!this->lookAtPoint(pos)) { panToCenter(panningplane, posn); this->interactiveCountDec(); } processed = TRUE; } } this->button3down = press; break; case SoMouseButtonEvent::BUTTON4: doZoom(viewer->getCamera(), TRUE, posn); processed = TRUE; break; case SoMouseButtonEvent::BUTTON5: doZoom(viewer->getCamera(), FALSE, posn); processed = TRUE; break; default: break; } } // Mouse Movement handling if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { this->lockrecenter = TRUE; const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (this->currentmode == NavigationStyle::ZOOMING) { this->zoomByCursor(posn, prevnormalized); processed = TRUE; } else if (this->currentmode == NavigationStyle::PANNING) { float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = TRUE; } else if (this->currentmode == NavigationStyle::DRAGGING) { this->addToLog(event->getPosition(), event->getTime()); this->spin(posn); processed = TRUE; } } // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev); if (event) this->processMotionEvent(event); processed = TRUE; } enum { BUTTON1DOWN = 1 << 0, BUTTON3DOWN = 1 << 1, CTRLDOWN = 1 << 2, SHIFTDOWN = 1 << 3, BUTTON2DOWN = 1 << 4 }; unsigned int combo = (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0); switch (combo) { case 0: if (curmode == NavigationStyle::SPINNING) { break; } newmode = NavigationStyle::IDLE; // The left mouse button has been released right now but // we want to avoid that the event is procesed elsewhere if (this->lockButton1) { this->lockButton1 = FALSE; processed = TRUE; } //if (curmode == NavigationStyle::DRAGGING) { // if (doSpin()) // newmode = NavigationStyle::SPINNING; //} break; case BUTTON1DOWN: // make sure not to change the selection when stopping spinning if (curmode == NavigationStyle::SPINNING || this->lockButton1) newmode = NavigationStyle::IDLE; else newmode = NavigationStyle::SELECTION; break; case BUTTON3DOWN: if (curmode == NavigationStyle::SPINNING) { break; } else if (newmode == NavigationStyle::ZOOMING) { break; } newmode = NavigationStyle::PANNING; if (curmode == NavigationStyle::DRAGGING) { if (doSpin()) { newmode = NavigationStyle::SPINNING; break; } } break; case CTRLDOWN|BUTTON2DOWN: newmode = NavigationStyle::PANNING; break; case SHIFTDOWN|BUTTON2DOWN: newmode = NavigationStyle::DRAGGING; break; case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN: newmode = NavigationStyle::ZOOMING; break; //case CTRLDOWN: //case CTRLDOWN|BUTTON1DOWN: //case CTRLDOWN|SHIFTDOWN: //case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN: // newmode = NavigationStyle::SELECTION; // break; //case BUTTON1DOWN|BUTTON3DOWN: //case CTRLDOWN|BUTTON3DOWN: // newmode = NavigationStyle::ZOOMING; // break; // There are many cases we don't handle that just falls through to // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN, // SHIFTDOWN|BUTTON3DOWN, SHIFTDOWN|CTRLDOWN|BUTTON3DOWN, etc. // This is a feature, not a bug. :-) // // mortene. default: // The default will make a spin stop and otherwise not do // anything. //if ((curmode != NavigationStyle::SEEK_WAIT_MODE) && // (curmode != NavigationStyle::SEEK_MODE)) { // newmode = NavigationStyle::IDLE; //} break; } if (newmode != curmode) { this->setViewingMode(newmode); } // If for dragging the buttons 1 and 3 are pressed // but then button 3 is relaesed we shouldn't switch // into selection mode. if (this->button1down && this->button3down) this->lockButton1 = TRUE; // If not handled in this class, pass on upwards in the inheritance // hierarchy. if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) processed = inherited::processSoEvent(ev); else return TRUE; return processed; }
SbBool OpenCascadeNavigationStyle::processSoEvent(const SoEvent * const ev) { // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); const SbVec2s size(vp.getViewportSizePixels()); const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not // necessary to restrict ourselves to only do one "action" for an // event, we only need this flag to see if any processing happened // at all. SbBool processed = false; const ViewerMode curmode = this->currentmode; ViewerMode newmode = curmode; // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. if (this->ctrldown != ev->wasCtrlDown()) { this->ctrldown = ev->wasCtrlDown(); } if (this->shiftdown != ev->wasShiftDown()) { this->shiftdown = ev->wasShiftDown(); } if (this->altdown != ev->wasAltDown()) { this->altdown = ev->wasAltDown(); } // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!processed && !viewer->isEditing()) { processed = handleEventInForeground(ev); if (processed) return true; } // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; switch (event->getKey()) { case SoKeyboardEvent::LEFT_CONTROL: case SoKeyboardEvent::RIGHT_CONTROL: this->ctrldown = press; break; case SoKeyboardEvent::LEFT_SHIFT: case SoKeyboardEvent::RIGHT_SHIFT: this->shiftdown = press; break; case SoKeyboardEvent::LEFT_ALT: case SoKeyboardEvent::RIGHT_ALT: this->altdown = press; break; case SoKeyboardEvent::H: processed = true; viewer->saveHomePosition(); break; case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: if (!this->isViewing()) this->setViewing(true); break; default: break; } } // Mouse Button / Spaceball Button handling if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; switch (button) { case SoMouseButtonEvent::BUTTON1: this->lockrecenter = true; this->button1down = press; if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = true; } else if (!press && (this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::IDLE; processed = true; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { this->setViewing(false); processed = true; } else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; } break; case SoMouseButtonEvent::BUTTON2: // If we are in edit mode then simply ignore the RMB events // to pass the event to the base class. this->lockrecenter = true; if (!viewer->isEditing()) { // If we are in zoom or pan mode ignore RMB events otherwise // the canvas doesn't get any release events if (this->currentmode != NavigationStyle::ZOOMING && this->currentmode != NavigationStyle::PANNING && this->currentmode != NavigationStyle::DRAGGING) { if (this->isPopupMenuEnabled()) { if (!press) { // release right mouse button this->openPopupMenu(event->getPosition()); } } } } // Alternative way of rotating & zooming if (press && (this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING)) { newmode = NavigationStyle::DRAGGING; saveCursorPosition(ev); this->centerTime = ev->getTime(); processed = true; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { newmode = NavigationStyle::IDLE; processed = true; } this->button2down = press; break; case SoMouseButtonEvent::BUTTON3: if (press) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue()); this->lockrecenter = false; } else if (!press && (this->currentmode == NavigationStyle::PANNING)) { newmode = NavigationStyle::IDLE; processed = true; } this->button3down = press; break; case SoMouseButtonEvent::BUTTON4: case SoMouseButtonEvent::BUTTON5: doZoom(viewer->getSoRenderManager()->getCamera(), button == SoMouseButtonEvent::BUTTON4, posn); processed = true; break; default: break; } } enum { BUTTON1DOWN = 1 << 0, BUTTON3DOWN = 1 << 1, CTRLDOWN = 1 << 2, SHIFTDOWN = 1 << 3, BUTTON2DOWN = 1 << 4 }; unsigned int combo = (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0); // Mouse Movement handling if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { this->lockrecenter = true; const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (this->currentmode == NavigationStyle::ZOOMING) { // OCCT uses horizontal mouse position, not vertical // this->zoomByCursor(posn, prevnormalized); float value = (posn[0] - prevnormalized[0]) * 10.0f; if (this->invertZoom) value = -value; zoom(viewer->getSoRenderManager()->getCamera(), value); processed = true; } else if (this->currentmode == NavigationStyle::PANNING) { float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = true; } else if (this->currentmode == NavigationStyle::DRAGGING) { this->addToLog(event->getPosition(), event->getTime()); this->spin(posn); moveCursorPosition(); processed = true; } else if (combo == (CTRLDOWN|BUTTON1DOWN)) { newmode = NavigationStyle::ZOOMING; } } // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev); if (event) this->processMotionEvent(event); processed = true; } switch (combo) { case 0: if (curmode == NavigationStyle::SPINNING) { break; } newmode = NavigationStyle::IDLE; break; case CTRLDOWN|BUTTON1DOWN: case BUTTON1DOWN: if (newmode != NavigationStyle::ZOOMING) newmode = NavigationStyle::SELECTION; break; case CTRLDOWN|BUTTON3DOWN: case BUTTON3DOWN: newmode = NavigationStyle::PANNING; break; case CTRLDOWN|BUTTON2DOWN: newmode = NavigationStyle::DRAGGING; break; case BUTTON2DOWN: newmode = NavigationStyle::IDLE; break; default: break; } if (newmode != curmode) { this->setViewingMode(newmode); } // If not handled in this class, pass on upwards in the inheritance // hierarchy. if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed) processed = inherited::processSoEvent(ev); else return true; return processed; }
SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) { // Events when in "ready-to-seek" mode are ignored, except those // which influence the seek mode itself -- these are handled further // up the inheritance hierarchy. if (this->isSeekMode()) { return inherited::processSoEvent(ev); } // Switch off viewing mode (Bug #0000911) if (!this->isSeekMode()&& !this->isAnimating() && this->isViewing() ) this->setViewing(false); // by default disable viewing mode to render the scene const SoType type(ev->getTypeId()); const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); const SbVec2s size(vp.getViewportSizePixels()); const SbVec2f prevnormalized = this->lastmouseposition; const SbVec2s pos(ev->getPosition()); const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); this->lastmouseposition = posn; // Set to true if any event processing happened. Note that it is not // necessary to restrict ourselves to only do one "action" for an // event, we only need this flag to see if any processing happened // at all. SbBool processed = false; const ViewerMode curmode = this->currentmode; ViewerMode newmode = curmode; // Mismatches in state of the modifier keys happens if the user // presses or releases them outside the viewer window. if (this->ctrldown != ev->wasCtrlDown()) { this->ctrldown = ev->wasCtrlDown(); } if (this->shiftdown != ev->wasShiftDown()) { this->shiftdown = ev->wasShiftDown(); } if (this->altdown != ev->wasAltDown()) { this->altdown = ev->wasAltDown(); } // give the nodes in the foreground root the chance to handle events (e.g color bar) if (!viewer->isEditing()) { processed = handleEventInForeground(ev); if (processed) return true; } // Keyboard handling if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; switch (event->getKey()) { case SoKeyboardEvent::LEFT_CONTROL: case SoKeyboardEvent::RIGHT_CONTROL: this->ctrldown = press; break; case SoKeyboardEvent::LEFT_SHIFT: case SoKeyboardEvent::RIGHT_SHIFT: this->shiftdown = press; break; case SoKeyboardEvent::LEFT_ALT: case SoKeyboardEvent::RIGHT_ALT: this->altdown = press; break; case SoKeyboardEvent::H: processed = true; viewer->saveHomePosition(); break; case SoKeyboardEvent::S: case SoKeyboardEvent::HOME: case SoKeyboardEvent::LEFT_ARROW: case SoKeyboardEvent::UP_ARROW: case SoKeyboardEvent::RIGHT_ARROW: case SoKeyboardEvent::DOWN_ARROW: if (!this->isViewing()) this->setViewing(true); break; default: break; } } // Mouse Button / Spaceball Button handling if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; const int button = event->getButton(); const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; // SoDebugError::postInfo("processSoEvent", "button = %d", button); switch (button) { case SoMouseButtonEvent::BUTTON1: this->button1down = press; if (press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue()); this->lockrecenter = false; } else if (!press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)) { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // is it just a left click? if (tmp.getValue() < dci && !this->lockrecenter) { if (!this->lookAtPoint(pos)) { panToCenter(panningplane, posn); this->interactiveCountDec(); } processed = true; } } else if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) { newmode = NavigationStyle::SEEK_MODE; this->seekToPoint(pos); // implicitly calls interactiveCountInc() processed = true; this->lockrecenter = true; } else if (press && (this->currentmode == NavigationStyle::IDLE)) { this->setViewing(true); processed = true; this->lockrecenter = true; } else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) { this->setViewing(false); processed = true; this->lockrecenter = true; } else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) { processed = true; this->lockrecenter = true; } // issue #0002433: avoid to swallow the UP event if down the // scene graph somewhere a dialog gets opened else if (press) { SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // a double-click? if (tmp.getValue() < dci) { mouseDownConsumedEvent = *event; mouseDownConsumedEvent.setTime(ev->getTime()); processed = true; } else { mouseDownConsumedEvent.setTime(ev->getTime()); // 'ANY' is used to mark that we don't know yet if it will // be a double-click event. mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); } } else if (!press) { if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { // now handle the postponed event inherited::processSoEvent(&mouseDownConsumedEvent); mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); } } break; case SoMouseButtonEvent::BUTTON2: // If we are in edit mode then simply ignore the RMB events // to pass the event to the base class. this->lockrecenter = true; if (!viewer->isEditing()) { // If we are in zoom or pan mode ignore RMB events otherwise // the canvas doesn't get any release events if (this->currentmode != NavigationStyle::ZOOMING && this->currentmode != NavigationStyle::PANNING) { if (this->isPopupMenuEnabled()) { if (!press) { // release right mouse button this->openPopupMenu(event->getPosition()); } } } } this->button2down = press; break; case SoMouseButtonEvent::BUTTON3: if (press) { this->centerTime = ev->getTime(); float ratio = vp.getViewportAspectRatio(); SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio); this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue()); this->lockrecenter = false; } else { SbTime tmp = (ev->getTime() - this->centerTime); float dci = (float)QApplication::doubleClickInterval()/1000.0f; // is it just a middle click? if (tmp.getValue() < dci && !this->lockrecenter) { if (!this->lookAtPoint(pos)) { panToCenter(panningplane, posn); this->interactiveCountDec(); } processed = true; } } this->button3down = press; break; case SoMouseButtonEvent::BUTTON4: doZoom(viewer->getSoRenderManager()->getCamera(), true, posn); processed = true; break; case SoMouseButtonEvent::BUTTON5: doZoom(viewer->getSoRenderManager()->getCamera(), false, posn); processed = true; break; default: break; } } // Mouse Movement handling if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { this->lockrecenter = true; const SoLocation2Event * const event = (const SoLocation2Event *) ev; if (this->currentmode == NavigationStyle::ZOOMING) { this->zoomByCursor(posn, prevnormalized); processed = true; } else if (this->currentmode == NavigationStyle::PANNING) { float ratio = vp.getViewportAspectRatio(); panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); processed = true; } else if (this->currentmode == NavigationStyle::DRAGGING) { this->addToLog(event->getPosition(), event->getTime()); this->spin(posn); moveCursorPosition(); processed = true; } } // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * const event = static_cast<const SoMotion3Event *>(ev); if (event) this->processMotionEvent(event); processed = true; } enum { BUTTON1DOWN = 1 << 0, BUTTON3DOWN = 1 << 1, CTRLDOWN = 1 << 2, SHIFTDOWN = 1 << 3, BUTTON2DOWN = 1 << 4 }; unsigned int combo = (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) | (this->shiftdown ? SHIFTDOWN : 0); switch (combo) { case 0: if (curmode == NavigationStyle::SPINNING) { break; } newmode = NavigationStyle::IDLE; if (curmode == NavigationStyle::DRAGGING) { if (doSpin()) newmode = NavigationStyle::SPINNING; } break; case BUTTON1DOWN: if (newmode != NavigationStyle::DRAGGING) { saveCursorPosition(ev); } newmode = NavigationStyle::DRAGGING; break; case BUTTON3DOWN: case CTRLDOWN|SHIFTDOWN: case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN: newmode = NavigationStyle::PANNING; break; case CTRLDOWN: case CTRLDOWN|BUTTON1DOWN: case SHIFTDOWN: case SHIFTDOWN|BUTTON1DOWN: newmode = NavigationStyle::SELECTION; break; case BUTTON1DOWN|BUTTON3DOWN: case CTRLDOWN|BUTTON3DOWN: case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN: newmode = NavigationStyle::ZOOMING; break; // There are many cases we don't handle that just falls through to // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN, // SHIFTDOWN|BUTTON3DOWN, SHIFTDOWN|CTRLDOWN|BUTTON3DOWN, etc. // This is a feature, not a bug. :-) // // mortene. default: // The default will make a spin stop and otherwise not do // anything. if ((curmode != NavigationStyle::SEEK_WAIT_MODE) && (curmode != NavigationStyle::SEEK_MODE)) { newmode = NavigationStyle::IDLE; } break; } if (newmode != curmode) { this->setViewingMode(newmode); } // If not handled in this class, pass on upwards in the inheritance // hierarchy. if ((curmode == NavigationStyle::SELECTION || newmode == NavigationStyle::SELECTION || viewer->isEditing()) && !processed) processed = inherited::processSoEvent(ev); else return true; return processed; }