1// @configure_input@ 2 3/**************************************************************************\ 4 * Copyright (c) Kongsberg Oil & Gas Technologies AS 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 14 * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Neither the name of the copyright holder nor the names of its 19 * contributors may be used to endorse or promote products derived from 20 * this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33\**************************************************************************/ 34 35#define PRIVATE(obj) ((SoGuiGLWidgetP *)(obj->pimpl)) 36 37// ************************************************************************* 38 39/*! 40 \class So@Gui@GLWidget So@Gui@GLWidget.h Inventor/@Gui@/So@Gui@GLWidget.h 41 \brief The So@Gui@GLWidget class manages OpenGL contexts. 42 43 \ingroup components 44 45 This is the basic, abstract component class which sets up an OpenGL 46 canvas for its subclasses. 47 48 Application programmers will normally not use this class directly, 49 but rather through the interface of either its direct descendent; 50 So@Gui@RenderArea, or through one of the "rapid application 51 development"-style viewer subclasses. 52 53 \if SOQT_DOC 54 55 An important thing to know about embedding So@Gui@GLWidget derived 56 components into other @Gui@ widgets is that you need to set up 57 "focus proxying" to have events still be sent to the OpenGL canvas 58 widget. This is true for both the So@Gui@RenderArea aswell as all 59 the viewer components (like So@Gui@ExaminerViewer, 60 So@Gui@PlaneViewer etc). 61 62 As an example, if you embed an So@Gui@ExaminerViewer inside a QFrame 63 like this: 64 65 \code 66 QMainWindow * toplevel = new QMainWindow; 67 QFrame * frame = new QFrame(toplevel); 68 So@Gui@ExaminerViewer * viewer = new So@Gui@ExaminerViewer(toplevel); 69 \endcode 70 71 ...events from the keyboard will not always automatically be 72 forwarded to the viewer OpenGL canvas. This is the code you need to 73 add in this case: 74 75 \code 76 toplevel->setFocusProxy(viewer->getWidget()); 77 \endcode 78 79 \endif 80 81 \if SOWIN_DOC 82 83 For debugging purposes, SoWinGLWidget provides the 84 OIV_FORCE_PIXEL_FORMAT environment variable to make it possible to 85 override the pixel format chosen by the internal attribute match 86 algorithm. 87 88 \endif 89*/ 90 91// ************************************************************************* 92 93#ifdef HAVE_CONFIG_H 94#include <config.h> 95#endif // HAVE_CONFIG_H 96 97#include <Inventor/@Gui@/common/gl.h> 98#include <Inventor/@Gui@/So@Gui@GLWidget.h> 99#include <Inventor/@Gui@/So@Gui@GLWidgetP.h> 100 101// ************************************************************************* 102 103// All shared documentation for functions with specific 104// implementations in the individual toolkits. 105 106/*! 107 \fn So@Gui@GLWidget::So@Gui@GLWidget(@WIDGET@ const parent, const char * const name, const SbBool embed, const int glmodes, const SbBool build) 108 109 The constructor is protected, as this is an abstract class to only 110 be used by it's subclasses. 111*/ 112 113/*! 114 \fn So@Gui@GLWidget::~So@Gui@GLWidget() 115 116 Clean up all use of internal resources. 117 118 The destructor is protected, as this is an abstract class to only be 119 used by it's subclasses. 120*/ 121 122/*! 123 \fn void So@Gui@GLWidget::setBorder(const SbBool enable) 124 125 Specify whether or not there should be a border framing the OpenGL 126 canvas. The border will be 2 pixels wide. 127 128 The default is to display the OpenGL canvas with no border. 129 130 \sa isBorder() 131*/ 132 133/*! 134 \fn SbBool So@Gui@GLWidget::isBorder(void) const 135 136 Returns whether or not there's a border framing the OpenGL canvas. 137 138 \sa setBorder() 139*/ 140 141/*! 142 \fn void So@Gui@GLWidget::setOverlayRender(const SbBool onoff) 143 144 Turn on or off the use of overlay planes. 145 146 \sa isOverlayRender() 147*/ 148 149/*! 150 \fn SbBool So@Gui@GLWidget::isOverlayRender(void) const 151 152 Returns a flag indicating whether or not overplay planes are 153 currently used. 154 155 \sa setOverlayRender() 156*/ 157 158/*! 159 \fn void So@Gui@GLWidget::setDoubleBuffer(const SbBool enable) 160 161 Switch between single and double buffer mode for the OpenGL canvas. 162 The default is to use a single buffer canvas. 163 164 \sa isDoubleBuffer() 165*/ 166 167/*! 168 \fn SbBool So@Gui@GLWidget::isDoubleBuffer(void) const 169 170 Returns the status of the buffer mode. 171 172 \sa setDoubleBuffer() 173*/ 174 175/*! 176 \fn void So@Gui@GLWidget::setQuadBufferStereo(const SbBool enable) 177 178 Enables or disables OpenGL quad buffer stereo. 179*/ 180 181/*! 182 \fn SbBool So@Gui@GLWidget::isQuadBufferStereo(void) const 183 184 Returns \c TRUE if quad buffer stereo is enabled for this widget. 185*/ 186 187/*! 188 \fn void So@Gui@GLWidget::setAccumulationBuffer(const SbBool enable) 189 190 Enables/disables the OpenGL accumulation buffer. 191 192 For general information about accumulation buffers, confer with your 193 OpenGL reference documentation. 194 195 By default, the accumulation buffer will be attempted disabled. 196 Whether or not it will \e actually be disabled depends on what 197 OpenGL contexts are available on the system. It is perfectly 198 possible that the only usable contexts with regard to the other 199 settings (like double buffering and RGBA mode versus color index 200 mode) causes the context selection to choose an OpenGL format that 201 contains an accumulation buffer, even though it was not 202 requested. 203 204 Vice versa, one is not guaranteed to get accumulation buffers even 205 when requested through this function, either because they are not 206 available, or because they are only available in combination with 207 other OpenGL context settings that are not wanted (like single 208 buffers, non-accellerated rendering, etc). 209 210 If you try to enable accumulation buffers by using this function, 211 you should therefore in succession use the 212 So@Gui@GLWidget::getAccumulationBuffer() to query whether or not an 213 accumulation buffer could actually be set up. 214 215 \sa So@Gui@RenderArea::setAntiAliasing() 216*/ 217 218/*! 219 \fn SbBool So@Gui@GLWidget::getAccumulationBuffer(void) const 220 221 Returns whether the OpenGL accumulation buffer is enabled. 222 223 The returned flag will indicate whether or not accumulation buffers 224 are \e actually present, and not just parrot the input value to 225 So@Gui@GLWidget::setAccumulationBuffer(). See documentation of that 226 function for more information. 227*/ 228 229/*! 230 \fn void So@Gui@GLWidget::setStencilBuffer(const SbBool enable) 231 232 Enables/disables the OpenGL stencil buffer. 233 234 For general information about stencil buffers, confer with your 235 OpenGL reference documentation. 236 237 By default, the stencil buffer will be attempted disabled, but the 238 same notes apply for stencil buffers as for accumulation 239 buffers. For an explanation on the issue of stencil and accumulation 240 buffer availability, see the function documentation of 241 So@Gui@GLWidget::setAccumulationBuffer(). 242*/ 243 244/*! 245 \fn SbBool So@Gui@GLWidget::getStencilBuffer(void) const 246 247 Returns whether the OpenGL stencil buffer is enabled. 248 249 The returned flag will indicate whether or not stencil buffers are 250 \e actually present, in the same manner as for 251 So@Gui@GLWidget::getAccumulationBuffer(). See documentation of 252 So@Gui@GLWidget::setStencilBuffer(). 253*/ 254 255/*! 256 \fn void So@Gui@GLWidget::setAlphaChannel(const SbBool enable) 257 258 Enables/disables the alpha channel for the OpenGL context. 259*/ 260 261/*! 262 \fn SbBool So@Gui@GLWidget::getAlphaChannel(void) const 263 264 Returns whether the alpha channel is enabled for the OpenGL context. 265*/ 266 267/*! 268 \fn void So@Gui@GLWidget::setDrawToFrontBufferEnable(const SbBool enable) 269 270 If this is set to \c TRUE, rendering will happen in the front buffer 271 even if the current rendering mode is double buffered. 272*/ 273 274/*! 275 \fn SbBool So@Gui@GLWidget::isDrawToFrontBufferEnable(void) const 276 \sa setDrawToFrontBufferEnable() 277*/ 278 279/*! 280 \fn @WIDGET@ So@Gui@GLWidget::buildWidget(@WIDGET@ parent) 281 282 This method builds the component contents in the given \a parent 283 widget. For subclasses adding new user interface items, this method 284 is typically overridden in the following manner: 285 286 \code 287 @WIDGET@ MyOwnViewer::buildWidget(@WIDGET@ parent) 288 { 289 @WIDGET@ superw = <superclass>::buildWidget(parent); 290 // [then move superw within MyOwnViewer framework and add own 291 // user interface components] 292 } 293 \endcode 294*/ 295 296/*! 297 \fn virtual void So@Gui@GLWidget::redraw(void) 298 299 This method is invoked when the GL buffer needs to be redrawn. 300 */ 301 302/*! 303 \var SbBool So@Gui@GLWidget::waitForExpose 304 305 If this is \c TRUE, rendering should not be done yet. Upon the first 306 expose event of a newly created OpenGL widget, this variable will 307 be set to \c FALSE. 308*/ 309 310/*! 311 \var SbBool So@Gui@GLWidget::drawToFrontBuffer 312 313 If this is \c TRUE, rendering will happen in the front buffer even 314 if the current rendering mode is double buffered. 315*/ 316 317/*! 318 \fn @WIDGET@ So@Gui@GLWidget::getNormalWidget(void) const 319 320 \if SOQT_DOC 321 For SoQt, this returns the same widget pointer as that of 322 SoQtGLWidget::getGLWidget(). 323 \endif 324*/ 325 326/*! 327 \fn @WIDGET@ So@Gui@GLWidget::getOverlayWidget(void) const 328 329 Returns widget associated with overlay planes, or \c NULL if no 330 overlay planes are available. 331 332 \if SOQT_DOC 333 For the Qt toolkit, overlay planes is a feature of the QGLWidget, 334 and not seen at a separate widget entity. So this call will just 335 return the same widget reference as the SoQt::getGLWidget() call (if 336 overlay planes are supported). 337 \endif 338*/ 339 340/*! 341 \fn void So@Gui@GLWidget::setGLSize(const SbVec2s size) 342 Sets the size of the GL canvas. 343*/ 344 345/*! 346 \fn SbVec2s So@Gui@GLWidget::getGLSize(void) const 347 348 Return the dimensions of the OpenGL canvas. 349*/ 350 351/*! 352 \fn float So@Gui@GLWidget::getGLAspectRatio(void) const 353 354 Return the aspect ratio of the OpenGL canvas. 355*/ 356 357/*! 358 \fn void So@Gui@GLWidget::setGlxSize(const SbVec2s size) 359 This function has been renamed to the more appropriate setGLSize. 360 \sa setGLSize 361*/ 362 363/*! 364 \fn SbVec2s So@Gui@GLWidget::getGlxSize(void) const 365 This function has been renamed to the more appropriate getGLSize. 366 \sa getGLSize 367*/ 368 369/*! 370 \fn float So@Gui@GLWidget::getGlxAspectRatio(void) const 371 This function has been renamed to the more appropriate getGLAspectRatio. 372 \sa getGLAspectRatio 373*/ 374 375/*! 376 \fn @WIDGET@ So@Gui@GLWidget::getGLWidget(void) const 377 378 Returns a pointer to the toolkit-native GL widget. 379*/ 380 381/*! 382 \fn void So@Gui@GLWidget::widgetChanged(@WIDGET@ w) 383 384 This is the method which gets called whenever we change which OpenGL 385 widget is used. 386 387 Should be overridden in subclasses which directly or indirectly 388 store the return value from the So@Gui@GLWidget::getGLWidget() 389 method. 390 391 \sa sizeChanged() 392*/ 393 394/*! 395 \fn void So@Gui@GLWidget::processEvent(@EVENT@ anyevent) 396 397 Any events from the native window system that goes to the OpenGL 398 canvas gets piped through this method. 399 400 It is overridden in the subclasses to catch user interaction with 401 the render canvas in the viewers, aswell as forwarding relevant 402 events to the scenegraph. 403*/ 404 405/*! 406 \fn void So@Gui@GLWidget::glLockNormal(void) 407 408 This method calls make-current on the correct context and ups the 409 lock level. 410*/ 411 412/*! 413 \fn void So@Gui@GLWidget::glUnlockNormal(void) 414 415 This method drops the lock level. 416*/ 417 418/*! 419 \fn void So@Gui@GLWidget::glSwapBuffers(void) 420 Swap back buffer to front and vice versa. 421*/ 422 423/*! 424 \fn void So@Gui@GLWidget::glFlushBuffer(void) 425 426 Flush the current GL buffer. Simply calls glFlush(). 427*/ 428 429/*! 430 \fn void So@Gui@GLWidget::glLockOverlay(void) 431 432 This method calls make-current on the correct context and ups the 433 lock level. 434*/ 435 436/*! 437 \fn void So@Gui@GLWidget::glUnlockOverlay(void) 438 439 This method drops the lock level. 440*/ 441 442/*! 443 \fn unsigned long So@Gui@GLWidget::getOverlayTransparentPixel(void) 444 Returns the overlay transparent pixel. 445*/ 446 447/*! 448 \fn SbBool So@Gui@GLWidget::isRGBMode(void) 449 450 Returns \c TRUE if the normal GL context is in RGBA mode. 451 Return \c FALSE if color index mode is used. 452*/ 453 454/*! 455 \fn void So@Gui@GLWidget::redrawOverlay(void) 456 457 Renders the overlay scene graph. Default method is empty. Subclasses 458 should override this method. 459*/ 460 461/*! 462 \fn SbBool So@Gui@GLWidget::hasNormalGLArea(void) const 463 464 Will return \c TRUE if a normal GL drawing area exists. 465*/ 466 467/*! 468 \fn SbBool So@Gui@GLWidget::hasOverlayGLArea(void) const 469 470 Will return \c TRUE if an overlay GL drawing area exists. 471*/ 472 473/*! 474 \fn void So@Gui@GLWidget::initGraphic(void) 475 476 Will be called when GL widget should initialize graphic, after 477 the widget has been created. Default method enabled GL_DEPTH_TEST. 478*/ 479 480/*! 481 \fn void So@Gui@GLWidget::initOverlayGraphic(void) 482 483 Will be called after the overlay widget has been created, and subclasses 484 should override this to initialize overlay stuff. 485 486 Default method does nothing. 487*/ 488 489/*! 490 \fn SbBool So@Gui@GLWidget::glScheduleRedraw(void) 491 492 Will be called whenever scene graph needs to be redrawn. If this 493 method return \c FALSE, redraw() will be called immediately. 494 495 Default method simply returns \c FALSE. Override this method to 496 schedule a redraw and return \c TRUE if you're trying to do The 497 Right Thing. 498*/ 499 500/*! 501 \fn void So@Gui@GLWidget::setStealFocus(SbBool enable) 502 503 Sets whether the GL widget should steal keyboard focus when the 504 mouse is over the GL view. 505 506 Default is \c TRUE. 507 508 \sa isStealFocus 509 \since So@Gui@ 1.3.0 510*/ 511 512/*! 513 \fn SbBool So@Gui@GLWidget::isStealFocus(void) const 514 515 Returns whether focus stealing policy is on (\c TRUE) or off (\c 516 FALSE). 517 518 Default is \c TRUE. 519 520 \sa setStealFocus 521 \since So@Gui@ 1.3.0 522*/ 523 524 525/*! 526 \fn void So@Gui@GLWidget::setSampleBuffers(const int numsamples) 527 528 Set the number of samples use when enabling multisample buffer contexts. 529 Multisampling will be enabled when numsamples > 1. 530 531*/ 532 533/*! 534 \fn int So@Gui@GLWidget::getSampleBuffers(void) const 535 536 Returns the number of samples used for multisampling. Returns 1 if 537 multisampling is disabled. 538*/ 539 540// Documented in common/SoGuiGLWidgetCommon.cpp.in. 541void 542So@Gui@GLWidget::setStealFocus(SbBool enable) 543{ 544 PRIVATE(this)->stealFocus = enable; 545} 546 547// Documented in common/SoGuiGLWidgetCommon.cpp.in. 548SbBool 549So@Gui@GLWidget::isStealFocus(void) const 550{ 551 return PRIVATE(this)->stealFocus; 552} 553 554// ************************************************************************* 555 556/*! 557 This function is provided as a convenience for the application 558 programmer to help with acquiring the OpenGL implementation limits 559 for rendering points. 560 561 For robust application code, one needs to consider the range limits 562 when setting the SoDrawStyle::pointSize field. 563*/ 564void 565So@Gui@GLWidget::getPointSizeLimits(SbVec2f & range, float & granularity) 566{ 567 this->glLockNormal(); 568 569 GLfloat vals[2]; 570 glGetFloatv(GL_POINT_SIZE_RANGE, vals); 571 572 // Matthias Koenig reported on coin-discuss that the OpenGL 573 // implementation on SGI Onyx 2 InfiniteReality returns 0 for the 574 // lowest pointsize, but it will still set the return value of 575 // glGetError() to GL_INVALID_VALUE if this size is attempted 576 // used. So the boundary range fix in the next line of code is a 577 // workaround for that OpenGL implementation bug. 578 // 579 // 0.0f and lower values are explicitly disallowed, according to 580 // the OpenGL 1.3 specification, Chapter 3.3. 581 582 if (vals[0] <= 0.0f) { vals[0] = So@Gui@Min(1.0f, vals[1]); } 583 584 range.setValue(vals[0], vals[1]); 585 586 GLfloat gran[1]; 587 glGetFloatv(GL_POINT_SIZE_GRANULARITY, gran); 588 granularity = gran[0]; 589 590 this->glUnlockNormal(); 591} 592 593/*! 594 This function is provided as a convenience for the application 595 programmer to help with acquiring the OpenGL implementation limits 596 for rendering lines. 597 598 For robust application code, one needs to consider the range limits 599 when setting the SoDrawStyle::lineWidth field. 600*/ 601void 602So@Gui@GLWidget::getLineWidthLimits(SbVec2f & range, float & granularity) 603{ 604 this->glLockNormal(); 605 606 GLfloat vals[2]; 607 glGetFloatv(GL_LINE_WIDTH_RANGE, vals); 608 609 // Matthias Koenig reported on coin-discuss that the OpenGL 610 // implementation on SGI Onyx 2 InfiniteReality returns 0 for the 611 // lowest linewidth, but it will still set the return value of 612 // glGetError() to GL_INVALID_VALUE if this size is attempted 613 // used. This is a workaround for what looks like an OpenGL bug. 614 615 if (vals[0] <= 0.0f) { vals[0] = So@Gui@Min(1.0f, vals[1]); } 616 617 range.setValue(vals[0], vals[1]); 618 619 GLfloat gran[1]; 620 glGetFloatv(GL_LINE_WIDTH_GRANULARITY, gran); 621 granularity = gran[0]; 622 623 this->glUnlockNormal(); 624} 625 626// FIXME: other implementation specifics to check are 627// 628// * maximum stack depths (attribute, modelview matrix, name, 629// projection matrix, texture matrix) 630// 631// * max display list nesting 632// 633// * max nr of clipplanes 634// 635// * max nr of light sources 636// 637// * max 3D texture size (needs specific extension?) 638// 639// 20020802 mortene. 640 641/*! 642 Sets whether OpenGL stereo buffers (quad buffer stereo) should be 643 used. 644*/ 645void 646So@Gui@GLWidget::setStereoBuffer(SbBool flag) 647{ 648 // FIXME: is this really correct? 20011012 mortene. 649 this->setQuadBufferStereo(flag); 650} 651 652/*! 653 Returns whether OpenGL stereo buffers are being used. 654*/ 655SbBool 656So@Gui@GLWidget::isStereoBuffer(void) const 657{ 658 // FIXME: is this really correct? 20011012 mortene. 659 return this->isQuadBufferStereo(); 660} 661 662// ************************************************************************* 663 664#ifndef DOXYGEN_SKIP_THIS 665 666// Remaining code is for the SoGuiGLWidgetP "private implementation" 667// class. 668 669 670SoGuiGLWidgetP::SoGuiGLWidgetP(So@Gui@GLWidget * publ) 671{ 672 this->pub = publ; 673 this->stealFocus = TRUE; 674} 675 676SoGuiGLWidgetP::~SoGuiGLWidgetP() 677{ 678} 679 680// Just forward from a static function, so we can find out from 681// anywhere within the library -- without exposing the API for the app 682// programmer. 683SbBool 684SoGuiGLWidgetP::isDirectRendering(So@Gui@GLWidget * w) 685{ 686 return ((SoGuiGLWidgetP *)(w->pimpl))->isDirectRendering(); 687} 688 689#undef PRIVATE 690#endif // DOXYGEN_SKIP_THIS 691 692// ************************************************************************* 693