/**************************************************************************\ * * This file is part of the Coin 3D visualization library. * Copyright (C) 1998-2007 by Systems in Motion. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * ("GPL") version 2 as published by the Free Software Foundation. * See the file LICENSE.GPL at the root directory of this source * distribution for additional information about the GNU GPL. * * For using Coin with software that can not be combined with the GNU * GPL, and for taking advantage of the additional benefits of our * support services, please contact Systems in Motion about acquiring * a Coin Professional Edition License. * * See http://www.coin3d.org/ for more information. * * Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY. * http://www.sim.no/ sales@sim.no coin-support@coin3d.org * \**************************************************************************/ /*! \class SbViewportRegion SbViewportRegion.h Inventor/SbViewportRegion.h \brief The SbViewportRegion class is a viewport within a full window. \ingroup base The SbViewportRegion class contains information to represent a subview within a window. It stores information about the origin and size of the subview, aswell as the size of the underlying "full" window. Available methods include inquiries and manipulation in both normalized coordinates and pixel coordinates. Below is a small example showing how the viewport of a viewer class can be modified, within a "proper" Coin and window system context. Hit 'D' or 'U' to move the viewport region 40 pixels down or up, respectively. Click 'Esc' and zoom with left + middle mouse buttons, to see how the region is defined, where no 3D geometry will be visible outside it. Click 'Esc' again to use 'U' and 'D'. \code // Copyright (C) 2000-2005 by Systems in Motion. All rights reserved. #include #include #include #include #include #include // ************************************************************ static void keypresscbfunc(void * userdata, SoEventCallback * keyboardcb) { SoQtExaminerViewer * viewer = (SoQtExaminerViewer *)userdata; const SoEvent * event = keyboardcb->getEvent(); int shift = 0; if (SO_KEY_PRESS_EVENT(event, U)) { shift = 40; keyboardcb->setHandled(); } else if (SO_KEY_PRESS_EVENT(event, D)) { shift = -40; keyboardcb->setHandled(); } if (keyboardcb->isHandled()) { SbViewportRegion vpr = viewer->getViewportRegion(); SbVec2s size = vpr.getViewportSizePixels(); SbVec2s origin = vpr.getViewportOriginPixels(); origin[1] -= shift; vpr.setViewportPixels(origin, size); viewer->setViewportRegion(vpr); } } // ************************************************************ int main(int argc, char ** argv) { QWidget * window = SoQt::init(argv[0]); SoSeparator * root = new SoSeparator; root->ref(); root->addChild(new SoCone); SoQtExaminerViewer * viewer = new SoQtExaminerViewer(window); SoEventCallback * eventcb = new SoEventCallback; eventcb->addEventCallback(SoKeyboardEvent::getClassTypeId(), keypresscbfunc, viewer); root->insertChild(eventcb, 0); viewer->setViewing(FALSE); viewer->setDecoration(FALSE); viewer->setSceneGraph(root); viewer->show(); SoQt::show(window); SoQt::mainLoop(); delete viewer; root->unref(); return 0; } \endcode \sa SbViewVolume */ // FIXME: should do a simple illustration in the class documentation // of the "viewport-within-a-window" concept which this class // represents. 20020103 mortene. #include #include #include /*! The default SbViewportRegion constructor initializes the viewport to fully cover a [100, 100] size window with 72 pixels per inch resolution. */ SbViewportRegion::SbViewportRegion(void) : winsize(100, 100), vporigin(0.0f, 0.0f), vpsize(1.0f, 1.0f) { this->pixperinch = 72.0f; } /*! Construct and initialize an SbViewportRegion instance with the given pixel value window dimensions. The viewport within this window will be set to cover the window completely. */ SbViewportRegion::SbViewportRegion(short width, short height) : winsize(width, height), vporigin(0,0), vpsize(1.0f, 1.0f) { #if COIN_DEBUG if (width<0) { SoDebugError::postWarning("SbViewportRegion::SbViewportRegion", "width (%d) should be >=0. Clamped to 0.", width); winsize[0]=0; } if (height<0) { SoDebugError::postWarning("SbViewportRegion::SbViewportRegion", "height (%d) should be >=0. Clamped to 0.", height); winsize[1]=0; } #endif // COIN_DEBUG this->pixperinch = 72.0f; } /*! Construct and initialize an SbViewportRegion instance with the given pixel value window dimensions. The viewport within this window will be set to cover the window completely. */ SbViewportRegion::SbViewportRegion(SbVec2s winsizearg) : winsize(winsizearg), vporigin(0,0), vpsize(1.0f, 1.0f) { #if COIN_DEBUG if (winsizearg[0]<0) { SoDebugError::postWarning("SbViewportRegion::SbViewportRegion", "winsize[0] (%d) should be >=0. Clamped to 0.", winsizearg[0]); this->winsize[0]=0; } if (winsizearg[1]<0) { SoDebugError::postWarning("SbViewportRegion::SbViewportRegion", "winsize[1] (%d) should be >=0. Clamped to 0.", winsizearg[1]); this->winsize[1]=0; } #endif // COIN_DEBUG this->pixperinch = 72.0f; } /*! Copy constructor. */ SbViewportRegion::SbViewportRegion(const SbViewportRegion & vpReg) { *this = vpReg; } /*! Set the window size in pixels. The viewport rectangle dimensions will stay intact. \sa getWindowSize() */ void SbViewportRegion::setWindowSize(short width, short height) { #if COIN_DEBUG if (width<0) { SoDebugError::postWarning("SbViewportRegion::setWindowSize", "width (%d) should be >=0. Clamped to 0.",width); width=0; } if (height<0) { SoDebugError::postWarning("SbViewportRegion::setWindowSize", "height (%d) should be >=0. Clamped to 0.", height); height=0; } #endif // COIN_DEBUG this->winsize.setValue(width, height); } /*! \overload */ void SbViewportRegion::setWindowSize(SbVec2s winsizearg) { #if COIN_DEBUG if (winsizearg[0]<0) { SoDebugError::postWarning("SbViewportRegion::setWindowSize", "winsize[0] (%d) should be >=0. Clamped to 0.", winsizearg[0]); winsizearg[0]=0; } if (winsizearg[1]<0) { SoDebugError::postWarning("SbViewportRegion::setWindowSize", "winsize[1] (%d) should be >=0. Clamped to 0.", winsizearg[1]); winsizearg[1]=0; } #endif // COIN_DEBUG this->setWindowSize(winsizearg[0], winsizearg[1]); } /*! Set up the origin and size of the viewport region in normalized coordinates. \sa getViewportOrigin(), getViewportSize(), setViewportPixels(). */ void SbViewportRegion::setViewport(float left, float bottom, float width, float height) { #if COIN_DEBUG if (width<0) { SoDebugError::postWarning("SbViewportRegion::setViewport", "width (%d) should be >=0. Clamped to 0.",width); width=0; } if (height<0) { SoDebugError::postWarning("SbViewportRegion::setViewport", "height (%d) should be >=0. Clamped to 0.", height); height=0; } #endif // COIN_DEBUG this->vporigin.setValue(left, bottom); this->vpsize.setValue(width, height); } /*! \overload */ void SbViewportRegion::setViewport(SbVec2f origin, SbVec2f size) { #if COIN_DEBUG if (size[0]<0) { SoDebugError::postWarning("SbViewportRegion::setViewport", "size[0] (%d) should be >=0. Clamped to 0.", size[0]); size[0]=0; } if (size[1]<0) { SoDebugError::postWarning("SbViewportRegion::setViewport", "size[1] (%d) should be >=0. Clamped to 0.", size[1]); size[1]=0; } #endif // COIN_DEBUG this->setViewport(origin[0], origin[1], size[0], size[1]); } /*! Set up the origin and size of the viewport region in pixel coordinates. \sa getViewportOriginPixels(), getViewportSizePixels(), setViewport() */ void SbViewportRegion::setViewportPixels(short left, short bottom, short width, short height) { #if COIN_DEBUG if (width<0) { SoDebugError::postWarning("SbViewportRegion::setViewportPixels", "width (%d) should be >=0. Clamped to 0.",width); width=0; } if (height<0) { SoDebugError::postWarning("SbViewportRegion::setViewportPixels", "height (%d) should be >=0. Clamped to 0.", height); height=0; } #endif // COIN_DEBUG this->vporigin.setValue(((float)left)/((float)this->winsize[0]), ((float)bottom)/((float)this->winsize[1])); this->vpsize.setValue(((float)width)/((float)this->winsize[0]), ((float)height)/((float)this->winsize[1])); } /*! \overload */ void SbViewportRegion::setViewportPixels(SbVec2s origin, SbVec2s size) { #if COIN_DEBUG if (size[0]<0) { SoDebugError::postWarning("SbViewportRegion::setViewportPixels", "size[0] (%d) should be >=0. Clamped to 0.", size[0]); size[0]=0; } if (size[1]<0) { SoDebugError::postWarning("SbViewportRegion::setViewportPixels", "size[1] (%d) should be >=0. Clamped to 0.", size[1]); size[1]=0; } #endif // COIN_DEBUG this->setViewportPixels(origin[0], origin[1], size[0], size[1]); } /*! Returns window dimensions (which are in absolute (i.e. pixel) coordinates). \sa setWindowSize(). */ const SbVec2s& SbViewportRegion::getWindowSize(void) const { return this->winsize; } /*! Return normalized viewport origin coordinates. \sa setViewport(), getViewportOriginPixels(). */ const SbVec2f & SbViewportRegion::getViewportOrigin(void) const { return this->vporigin; } /* Rounds off the given fractional number to the nearest short integer. */ static inline short round2short(float a) { if (a == (float) (short(a))) return short(a); else return (a>0.0f) ? short(a+0.5f) : -short(0.5f-a); } /*! Return viewport origin coordinates in pixel values. \sa setViewportPixels(), getViewportOrigin(). */ const SbVec2s & SbViewportRegion::getViewportOriginPixels(void) const { // Cast away constness. Ugly. SbViewportRegion * thisp = (SbViewportRegion *)this; // FIXME: the tmp storage seems totally unnecessary? 20040213 mortene. thisp->vporigin_s.setValue(round2short(this->winsize[0] * this->vporigin[0]), round2short(this->winsize[1] * this->vporigin[1])); return this->vporigin_s; } /*! Returns the normalized viewport size. \sa setViewport(), getViewportSizePixels(). */ const SbVec2f & SbViewportRegion::getViewportSize(void) const { return this->vpsize; } /*! Returns viewport size in pixel coordinates. \sa setViewportPixels(), getViewportSize(). */ const SbVec2s & SbViewportRegion::getViewportSizePixels(void) const { // Cast away constness. Ugly. SbViewportRegion * thisp = (SbViewportRegion *)this; // FIXME: the tmp storage seems totally unnecessary? 20040213 mortene. thisp->vpsize_s = SbVec2s(round2short(this->winsize[0] * this->vpsize[0]), round2short(this->winsize[1] * this->vpsize[1])); return this->vpsize_s; } /*! Returns the aspect ratio of the viewport region. The aspect ratio is calculated as pixelwidth divided on pixelheight. */ float SbViewportRegion::getViewportAspectRatio(void) const { SbVec2s size = this->getViewportSizePixels(); if (size[1] == 0) return 1.0; return float(size[0])/float(size[1]); } /*! Scale the width of the viewport region. The scale factor should not make the viewport larger than the window. If this happens, the viewport will be clamped. The scaling will be done around the viewport region center point, but if this causes the viewport origin to be moved below (0,0), the origin coordinates will be clamped. \sa scaleHeight(). */ void SbViewportRegion::scaleWidth(float ratio) { #if COIN_DEBUG if (ratio<0.0f) { SoDebugError::postWarning("SbViewportRegion::scaleWidth", "ratio (%f) should be >=0.0f. Clamped to 0.0f.", ratio); ratio=0.0f; } #endif // COIN_DEBUG float oldw = this->vpsize[0]; this->vpsize[0] *= ratio; this->vporigin[0] -= (this->vpsize[0] - oldw) / 2.0f; if (this->vpsize[0] > 1.0f) this->vpsize[0] = 1.0f; if (this->vporigin[0] < 0.0f) this->vporigin[0] = 0.0f; } /*! Scale the height of the viewport region. The scale factor should not make the viewport larger than the window. If this happens, the viewport will be clamped. The scaling will be done around the viewport region center point, but if this causes the viewport origin to be moved below (0,0), the origin coordinates will be clamped. \sa scaleWidth(). */ void SbViewportRegion::scaleHeight(float ratio) { #if COIN_DEBUG if (ratio<0.0f) { SoDebugError::postWarning("SbViewportRegion::scaleheight", "ratio (%f) should be >=0.0f. Clamped to 0.0f.", ratio); ratio=0.0f; } #endif // COIN_DEBUG float oldh = this->vpsize[1]; this->vpsize[1] *= ratio; this->vporigin[1] -= (this->vpsize[1] - oldh) / 2.0f; if(this->vpsize[1] > 1.0f) this->vpsize[1] = 1.0f; if(this->vporigin[1] < 0.0f) this->vporigin[1] = 0.0f; } /*! Set pixels per inch. Default value is 72. \sa getPixelsPerInch(). */ void SbViewportRegion::setPixelsPerInch(float ppi) { #if COIN_DEBUG if (ppi<0.0f) { SoDebugError::postWarning("SbViewportRegion::setPixelsPerInch", "ppi value (%f) should be >=0.0f. " "Clamped to 0.0f.",ppi); ppi=0.0f; } #endif // COIN_DEBUG this->pixperinch = ppi; } /*! Get pixels per inch. \sa setPixelsPerInch(). */ float SbViewportRegion::getPixelsPerInch(void) const { return this->pixperinch; } /*! Get pixels per point. A \e point is defined as something you can put 72 of per inch... \sa setPixelsPerInch(), getPixelsPerInch(). */ float SbViewportRegion::getPixelsPerPoint(void) const { return this->pixperinch / 72.0f; } /*! \relates SbViewportRegion Compares two SbViewportRegion instances for equality. */ int operator==(const SbViewportRegion & reg1, const SbViewportRegion & reg2) { return reg1.winsize == reg2.winsize && reg1.getViewportOriginPixels() == reg2.getViewportOriginPixels() && reg1.getViewportSizePixels() == reg2.getViewportSizePixels() && reg1.pixperinch == reg2.pixperinch; } /*! \relates SbViewportRegion Compares two SbViewportRegion instances for inequality. \since Coin 2.4 */ int operator!=(const SbViewportRegion & reg1, const SbViewportRegion & reg2) { return !(reg1 == reg2); } /*! Dump the state of this object to the \a file stream. Only works in debug version of library, method does nothing in an optimized compile. */ void SbViewportRegion::print(FILE * fp) const { #if COIN_DEBUG (void)fprintf( fp, " winsize: " ); this->getWindowSize().print(fp); (void)fprintf( fp, "\n" ); (void)fprintf( fp, " vporigin: " ); this->getViewportOrigin().print(fp); (void)fprintf( fp, "\n" ); (void)fprintf( fp, " vporiginpix: " ); this->getViewportOriginPixels().print(fp); (void)fprintf( fp, "\n" ); (void)fprintf( fp, " vpsize: " ); this->getViewportSize().print(fp); (void)fprintf( fp, "\n" ); (void)fprintf( fp, " vpsizepix: " ); this->getViewportSizePixels().print(fp); (void)fprintf( fp, "\n" ); (void)fprintf( fp, " aspectratio: %f\n", this->getViewportAspectRatio() ); (void)fprintf( fp, " ppi: %f\n", this->getPixelsPerInch() ); (void)fprintf( fp, " ppp: %f\n", this->getPixelsPerPoint() ); #endif // COIN_DEBUG }