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/**************************************************************************\ 36 * 37 * A WORD OF ADVICE 38 * 39 * It is fruitless to modify the contents of the So@Gui@RenderArea.cpp file 40 * because it is autogenerated by configure from the SoGuiRenderArea.cpp.in 41 * file which you will find in the src/Inventor/@Gui@/common/ directory. 42 * Do your modifications to that file instead. 43 * 44\**************************************************************************/ 45 46// ************************************************************************* 47 48/*! 49 \class So@Gui@RenderArea Inventor/@Gui@/So@Gui@RenderArea.h 50 \brief The So@Gui@RenderArea class adds scenegraph handling and event management. 51 52 \ingroup components viewers 53 54 The So@Gui@RenderArea class is a component that adds scenegraph 55 management and input device event handling to the So@Gui@GLWidget 56 component. 57 58 The class has many convenient methods for controlling aspects of the 59 rendering, like for instance transparency, aliasing and for 60 scheduling of redraws. 61 62 Native toolkit events are caught by So@Gui@RenderArea components, 63 translated to Coin SoEvent instances and passed on to the 64 scenegraph, in case the user is doing interactive operations on for 65 instance Coin geometry draggers. 66 67 68 So@Gui@RenderArea is the first non-abstract component in it's 69 inheritance hierarchy that you can use directly from client 70 application code to set up a scenegraph viewer canvas. 71 72 For an So@Gui@RenderArea component to properly display your 73 scenegraph, it must contain an SoCamera-derived node and at least 74 one SoLight-derived lightsource node. 75 76 Here's a complete, stand-alone example on how to set up an 77 So@Gui@RenderArea with a scenegraph: 78 79 \code 80 #include <Inventor/@Gui@/So@Gui@.h> 81 #include <Inventor/@Gui@/So@Gui@RenderArea.h> 82 83 #include <Inventor/nodes/SoCube.h> 84 #include <Inventor/nodes/SoRotor.h> 85 #include <Inventor/nodes/SoArray.h> 86 #include <Inventor/nodes/SoDirectionalLight.h> 87 #include <Inventor/nodes/SoPerspectiveCamera.h> 88 #include <Inventor/nodes/SoSeparator.h> 89 90 // Set up a simple scenegraph, just for demonstration purposes. 91 static SoSeparator * 92 get_scene_graph(void) 93 { 94 SoSeparator * root = new SoSeparator; 95 96 SoGroup * group = new SoGroup; 97 98 SoRotor * rotor = new SoRotor; 99 rotor->rotation = SbRotation(SbVec3f(0.2, 0.5, 0.9), M_PI/4.0); 100 group->addChild(rotor); 101 102 SoCube * cube = new SoCube; 103 group->addChild(cube); 104 105 SoArray * array = new SoArray; 106 array->origin = SoArray::CENTER; 107 array->addChild(group); 108 array->numElements1 = 2; 109 array->numElements2 = 2; 110 array->separation1 = SbVec3f(4, 0, 0); 111 array->separation2 = SbVec3f(0, 4, 0); 112 113 root->addChild(array); 114 return root; 115 } 116 117 int 118 main(int argc, char ** argv) 119 { 120 @WIDGET@ window = So@Gui@::init(argv[0]); 121 122 SoSeparator * root = new SoSeparator; 123 root->ref(); 124 125 SoPerspectiveCamera * camera; 126 root->addChild(camera = new SoPerspectiveCamera); 127 128 root->addChild(new SoDirectionalLight); 129 130 SoSeparator * userroot = get_scene_graph(); 131 root->addChild(userroot); 132 133 So@Gui@RenderArea * renderarea = new So@Gui@RenderArea(window); 134 camera->viewAll(userroot, renderarea->getViewportRegion()); 135 renderarea->setSceneGraph(root); 136 renderarea->setBackgroundColor(SbColor(0.0f, 0.2f, 0.3f)); 137 if (argc > 1) { 138 renderarea->setTitle(argv[1]); 139 renderarea->setIconTitle(argv[1]); 140 } 141 renderarea->show(); 142 143 So@Gui@::show(window); 144 So@Gui@::mainLoop(); 145 146 delete renderarea; 147 root->unref(); 148 149 return 0; 150 } 151 \endcode 152*/ 153 154// ************************************************************************* 155 156#include <Inventor/@Gui@/So@Gui@RenderArea.h> 157 158#include <string.h> // strchr() 159 160#ifdef HAVE_CONFIG_H 161#include <config.h> 162#endif // HAVE_CONFIG_H 163 164#if SOQT_DEBUG // For the "soinfo" debugging backdoor. 165#include <qgl.h> 166#include <qapplication.h> 167#endif // SOQT_DEBUG 168 169#include <Inventor/@Gui@/common/gl.h> // glDrawBuffer() 170 171#include <Inventor/SoSceneManager.h> 172#include <Inventor/actions/SoSearchAction.h> 173#include <Inventor/actions/SoWriteAction.h> 174#include <Inventor/errors/SoDebugError.h> 175#include <Inventor/events/SoKeyboardEvent.h> 176#include <Inventor/misc/SoBasic.h> 177#include <Inventor/nodekits/SoBaseKit.h> 178#include <Inventor/nodes/SoCamera.h> 179#include <Inventor/nodes/SoSelection.h> 180#include <Inventor/SoOffscreenRenderer.h> 181#include <Inventor/SbColor4f.h> 182 183#include <so@gui@defs.h> 184#include <Inventor/@Gui@/So@Gui@Basic.h> 185#include <Inventor/@Gui@/So@Gui@.h> 186#include <Inventor/@Gui@/devices/So@Gui@Keyboard.h> 187#include <Inventor/@Gui@/devices/So@Gui@Mouse.h> 188#ifdef HAVE_JOYSTICK_LINUX 189#include <Inventor/@Gui@/devices/So@Gui@LinuxJoystick.h> 190#endif // HAVE_JOYSTICK_LINUX 191#ifdef HAVE_SPACENAV_SUPPORT 192#include <Inventor/@Gui@/devices/So@Gui@SpacenavDevice.h> 193#endif // HAVE_SPACENAV_SUPPORT 194 195#include <Inventor/@Gui@/So@Gui@GLWidgetP.h> 196#include <Inventor/@Gui@/SoAny.h> 197 198#define RENDERAREA_DEBUG_REDRAWS 0 199 200#define PRIVATE(obj) ((obj)->pimpl) 201#define PUBLIC(obj) ((obj)->pub) 202 203// ************************************************************************* 204 205SO@GUI@_OBJECT_SOURCE(So@Gui@RenderArea); 206 207// ************************************************************************* 208 209#ifndef DOXYGEN_SKIP_THIS 210 211class So@Gui@RenderAreaP { 212public: 213 214 So@Gui@RenderAreaP(class So@Gui@RenderArea * pub); 215 ~So@Gui@RenderAreaP(void); 216 217 SbBool clear; 218 SbBool clearZBuffer; 219 SbBool clearOverlay; 220 221 SoSceneManager * normalManager; 222 SoSceneManager * overlayManager; 223 224 SbColor * normalColormap; 225 int normalColormapSize; 226 int normalColormapStart; 227 SbColor * overlayColormap; 228 int overlayColormapSize; 229 int overlayColormapStart; 230 231 SbPList * devicelist; 232 233 struct { 234 So@Gui@Keyboard * keyboard; 235 So@Gui@Mouse * mouse; 236#ifdef HAVE_SPACENAV_SUPPORT 237 So@Gui@SpacenavDevice * spacenav; 238#endif // HAVE_SPACENAV_SUPPORT 239 } devices; 240 241 SbBool autoRedraw; 242 243 void replaceSoSelectionMonitor(SoSelection * newsel, SoSelection * oldsel) const; 244 SoSelection * normalselection; 245 SoSelection * overlayselection; 246 247 static const int GL_DEFAULT_MODE; 248 249 void constructor(SbBool mouseInput, SbBool keyboardInput, SbBool build); 250 static void renderCB(void * user, SoSceneManager * manager); 251 static void selection_redraw_cb(void * data, SoSelection * sel); 252 void setDevicesWindowSize(const SbVec2s size); 253 254 // OpenGL info-window hack. 255 enum { NONE, OPENGL, INVENTOR, TOOLKIT, DUMPSCENEGRAPH, DUMPCAMERAS, OFFSCREENGRAB }; 256 int checkMagicSequences(const char c); 257 void showOpenGLDriverInformation(void); 258 void showInventorInformation(void); 259 void showToolkitInformation(void); 260 void dumpScenegraph(void); 261 void dumpCameras(void); 262 void offScreenGrab(void); 263 264 SbBool invokeAppCB(@EVENT@ event); 265 const SoEvent * getSoEvent(@EVENT@ event); 266 267 So@Gui@RenderAreaEventCB * appeventhandler; 268 void * appeventhandlerdata; 269 270private: 271 So@Gui@RenderArea * pub; // public interface class 272 SbString currentinput; // For the OpenGL info-window hack. 273}; 274 275const int So@Gui@RenderAreaP::GL_DEFAULT_MODE = (SO_GL_RGB | 276 SO_GL_ZBUFFER | 277 SO_GL_DOUBLE ); 278 279#if SO@GUI@_DEBUG && defined(__COIN__) 280// Disabled when compiling against SGI / TGS Inventor, as we're using 281// our Coin-specific extension SbString::sprintf() a lot. 282#define DEBUGGING_EGGS 1 283#endif // SO@GUI@_DEBUG && __COIN__ 284 285// Note: assumes a valid current OpenGL context. 286void 287So@Gui@RenderAreaP::showOpenGLDriverInformation(void) 288{ 289#if DEBUGGING_EGGS 290 const GLubyte * vendor = glGetString(GL_VENDOR); 291 const GLubyte * renderer = glGetString(GL_RENDERER); 292 const GLubyte * version = glGetString(GL_VERSION); 293 const GLubyte * extensions = glGetString(GL_EXTENSIONS); 294 295 SbString info = "GL_VENDOR: \""; info += (const char *)vendor; info += "\"\n"; 296 info += "GL_RENDERER: \""; info += (const char *)renderer; info += "\"\n"; 297 info += "GL_VERSION: \""; info += (const char *)version; info += "\"\n"; 298 info += "GL_EXTENSIONS: \"\n "; 299 300 SbString exts = (const char *)extensions; 301 const char * p; 302 int count = 0; 303 // (the extra parentheses in the while-expression kills a gcc warning) 304 while ((p = strchr(exts.getString(), ' '))) { 305 const char * start = exts.getString(); 306 info += exts.getSubString(0, p - start); 307 exts.deleteSubString(0, p - start); 308 count++; 309 if (count == 4) { // number of extensions listed on each line 310 info += "\n "; 311 count = 0; 312 } 313 } 314 if (exts.getLength() > 0) { info += "\n "; info += exts; } 315 info += "\"\n"; 316 317 // FIXME: should also show available GLX / WGL / AGL 318 // extensions. 20020802 mortene. 319 320 // Misc implementation info 321 { 322 SbVec2f range; 323 float granularity; 324 PUBLIC(this)->getPointSizeLimits(range, granularity); 325 326 SbString s; 327 s.sprintf("glPointSize(): range=[%f, %f], granularity=%f\n", 328 range[0], range[1], granularity); 329 info += s; 330 331 332 PUBLIC(this)->getLineWidthLimits(range, granularity); 333 334 s.sprintf("glLineWidth(): range=[%f, %f], granularity=%f\n", 335 range[0], range[1], granularity); 336 info += s; 337 338 GLint depthbits[1]; 339 glGetIntegerv(GL_DEPTH_BITS, depthbits); 340 s.sprintf("GL_DEPTH_BITS==%d\n", depthbits[0]); 341 info += s; 342 343 GLint colbits[4]; 344 glGetIntegerv(GL_RED_BITS, &colbits[0]); 345 glGetIntegerv(GL_GREEN_BITS, &colbits[1]); 346 glGetIntegerv(GL_BLUE_BITS, &colbits[2]); 347 glGetIntegerv(GL_ALPHA_BITS, &colbits[3]); 348 s.sprintf("GL_[RED|GREEN|BLUE|ALPHA]_BITS==[%d, %d, %d, %d]\n", 349 colbits[0], colbits[1], colbits[2], colbits[3]); 350 info += s; 351 352 GLint accumbits[4]; 353 glGetIntegerv(GL_ACCUM_RED_BITS, &accumbits[0]); 354 glGetIntegerv(GL_ACCUM_GREEN_BITS, &accumbits[1]); 355 glGetIntegerv(GL_ACCUM_BLUE_BITS, &accumbits[2]); 356 glGetIntegerv(GL_ACCUM_ALPHA_BITS, &accumbits[3]); 357 s.sprintf("GL_ACCUM_[RED|GREEN|BLUE|ALPHA]_BITS==[%d, %d, %d, %d]\n", 358 accumbits[0], accumbits[1], accumbits[2], accumbits[3]); 359 info += s; 360 361 GLint stencilbits; 362 glGetIntegerv(GL_STENCIL_BITS, &stencilbits); 363 s.sprintf("GL_STENCIL_BITS==%d\n", stencilbits); 364 info += s; 365 366 GLint maxdims[2]; 367 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxdims); 368 s.sprintf("GL_MAX_VIEWPORT_DIMS==<%d, %d>\n", maxdims[0], maxdims[1]); 369 info += s; 370 371 GLint texdim; 372 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texdim); 373 s.sprintf("GL_MAX_TEXTURE_SIZE==%d\n", texdim); 374 info += s; 375 376 GLint maxlights; 377 glGetIntegerv(GL_MAX_LIGHTS, &maxlights); 378 s.sprintf("GL_MAX_LIGHTS==%d\n", maxlights); 379 info += s; 380 381 GLint maxplanes; 382 glGetIntegerv(GL_MAX_CLIP_PLANES, &maxplanes); 383 s.sprintf("GL_MAX_CLIP_PLANES==%d\n", maxplanes); 384 info += s; 385 386 // FIXME: other implementation specifics to print are 387 // 388 // * maximum stack depths (attribute, modelview matrix, name, 389 // projection matrix, texture matrix) 390 // 391 // * max display list nesting 392 // 393 // * max 3D texture size (needs specific extension?) 394 // 395 // 20020802 mortene. 396 } 397 398 SbString s; 399 s.sprintf("\n" 400 "Rendering is %sdirect.\n", 401 SoGuiGLWidgetP::isDirectRendering(PUBLIC(this)) ? "" : "in"); 402 info += s; 403 404 So@Gui@::createSimpleErrorDialog(NULL, "OpenGL driver information", 405 info.getString()); 406#endif // DEBUGGING_EGGS 407} 408 409void 410So@Gui@RenderAreaP::showInventorInformation(void) 411{ 412#if DEBUGGING_EGGS 413 SbString info; 414 info.sprintf("%s\n", SoDB::getVersion()); 415 416 // Display calculated maximum resolution of SbTime::getTimeOfDay(). 417 { 418 const double DURATION = 0.2; // in seconds 419 SbTime current = SbTime::getTimeOfDay(); 420 SbTime end(current + DURATION); 421 SbTime last = current; 422 unsigned int ticks = 0; 423 do { 424 current = SbTime::getTimeOfDay(); 425 if (current.getValue() != last.getValue()) { ticks++; last = current; } 426 } while (current < end); 427 SbString s; 428 s.sprintf("\nSbTime::getTimeOfDay() resolution: ~ %d Hz\n", 429 (int)(((double)ticks) / DURATION)); 430 info += s; 431 } 432 433 // FIXME: dump list of available node classes? 20010927 mortene. 434 So@Gui@::createSimpleErrorDialog(NULL, "Inventor implementation info", 435 info.getString()); 436 437#endif // DEBUGGING_EGGS 438} 439 440void 441So@Gui@RenderAreaP::showToolkitInformation(void) 442{ 443#if DEBUGGING_EGGS 444 SbString info = "So@Gui@ version "; info += SO@GUI@_VERSION; info += "\n"; 445#if SO@GUI@_MAKE_DLL 446 info += "Built as MSWindows DLL.\n"; 447#endif // !SO@GUI@_MAKE_DLL 448 449 // FIXME: include information about the underlying toolkit library, 450 // if possible, like we do for Qt below (ie Gtk version, Motif 451 // implementation, MSWindows version, ...). 20010927 mortene. 452 453#ifdef SOQT_INTERNAL 454 // Qt implementation info. 455 { 456 SbString s; 457 s.sprintf("\nQt version: %s\n", qVersion()); 458 info += s; 459 } 460#endif // SOQT_INTERNAL 461 462 // FIXME: information about DLL path(s) (both for the So@Gui@ and 463 // Coin/Inventor library) would be _extremely_ useful for debugging 464 // "remote" applications, as application programmers (including 465 // ourselves) tend to spread those files around misc diskdrive 466 // directories -- especially on MSWindows platforms. Mismatches for 467 // run-time binding and link-time binding then causes bugs which are 468 // impossible to make sense of. 469 // 470 // I don't know if any platforms have enough introspection 471 // functionality to enable us to do this, though. Should 472 // investigate. (update: GetModuleHandle() looks like the place to 473 // start looking in the Win32 API.) 474 // 475 // 20010927 mortene. 476 477 // OpenGL canvas settings. 478 { 479 SbString s; 480 s.sprintf("\nCurrent OpenGL canvas:\n" 481 " %sbuffer\n" 482 " drawing to %sbuffer\n" 483 " %s rendering%s\n" 484 " %s mode\n" 485 " with%s overlay planes\n", 486 PUBLIC(this)->isDoubleBuffer() ? "double" : "single", 487 PUBLIC(this)->isDrawToFrontBufferEnable() ? "front" : "back", 488 PUBLIC(this)->isStereoBuffer() ? "stereo" : "mono", 489 PUBLIC(this)->isQuadBufferStereo() ? " (OpenGL quadbuffer)" : "", 490 PUBLIC(this)->isRGBMode() ? "RGB" : "colorindex", 491 PUBLIC(this)->isOverlayRender() ? "" : "out"); 492 493 // FIXME: information about the native OpenGL widget format? 494 // 20010927 mortene. 495 496 info += s; 497 } 498 499 // Underlying Inventor implementation. 500 { 501 SbString s; 502 s.sprintf("\nInventor implementation: %s\n", SoDB::getVersion()); 503 info += s; 504 } 505 506 So@Gui@::createSimpleErrorDialog(NULL, "So@Gui@ implementation info", 507 info.getString()); 508#endif // DEBUGGING_EGGS 509} 510 511void 512So@Gui@RenderAreaP::dumpScenegraph(void) 513{ 514#ifdef DEBUGGING_EGGS 515 SoOutput out; 516 SbString filename = SbTime::getTimeOfDay().format(); 517 filename += "-dump.iv"; 518 SbBool ok = out.openFile(filename.getString()); 519 if (!ok) { 520 SoDebugError::post("So@Gui@RenderAreaP::dumpScenegraph", 521 "couldn't open file '%s'", filename.getString()); 522 return; 523 } 524 SoWriteAction wa(&out); 525 wa.apply(this->normalManager->getSceneGraph()); 526 SoDebugError::postInfo("So@Gui@RenderAreaP::dumpScenegraph", 527 "dumped scenegraph to '%s'", filename.getString()); 528#endif // DEBUGGING_EGGS 529} 530 531void 532So@Gui@RenderAreaP::dumpCameras(void) 533{ 534#ifdef DEBUGGING_EGGS 535 const SbBool kitsearch = SoBaseKit::isSearchingChildren(); 536 SoBaseKit::setSearchingChildren(TRUE); 537 538 SoSearchAction search; 539 search.setType(SoCamera::getClassTypeId()); 540 search.setInterest(SoSearchAction::ALL); 541 search.setSearchingAll(TRUE); 542 search.apply(this->normalManager->getSceneGraph()); 543 544 SoBaseKit::setSearchingChildren(kitsearch); 545 546 const SoPathList & pl = search.getPaths(); 547 const unsigned int numcams = pl.getLength(); 548 SoDebugError::postInfo("So@Gui@RenderAreaP::dumpCameras", 549 "Number of cameras in scene graph: %d", 550 numcams); 551 552 for (unsigned int i = 0; i < numcams; i++) { 553 const SoPath * p = pl[i]; 554 SoNode * n = p->getTail(); 555 assert(n->isOfType(SoCamera::getClassTypeId())); 556 SoCamera * cam = (SoCamera *)n; 557 558 const SbVec3f pos = cam->position.getValue(); 559 const SbRotation rot = cam->orientation.getValue(); 560 SbVec3f axis; 561 float angle; 562 rot.getValue(axis, angle); 563 564 SoDebugError::postInfo("So@Gui@RenderAreaP::dumpCameras", 565 "type==%s, name=='%s', position==<%f, %f, %f>, " 566 "orientation-rotation==<%f, %f, %f>--%f", 567 cam->getTypeId().getName().getString(), 568 cam->getName().getString(), 569 pos[0], pos[1], pos[2], 570 axis[0], axis[1], axis[2], angle); 571 } 572#endif // DEBUGGING_EGGS 573} 574 575/* 576 Behaviour controlled by environment variables 577 COIN_SOGRAB_GEOMETRY (maximum geometry - on-screen aspect is preserved) 578 COIN_SOGRAB_FILENAME (filename template - can use %d to insert counter) 579 580 Examples: 581 export COIN_SOGRAB_GEOMETRY=1024x768 582 export COIN_SOGRAB_FILENAME=c:\\grab%03d.png 583 584*/ 585 586void 587So@Gui@RenderAreaP::offScreenGrab(void) 588{ 589#ifdef DEBUGGING_EGGS 590 static int maxwidth = -1; 591 static int maxheight = -1; 592 static int counter = 0; 593 static const char fallback_ext[] = ".rgb"; 594 static const char fallback_name[] = "coingrab%03d.rgb"; 595 596 /* 597 FIXME: 598 599 - schedule a regular render-pass and hook into the render 600 pipe-line to check all the interesting GL context features that 601 might need to be enabled for the offscreen renderer context. 602 Then set up the offscreen renderer context to match those 603 features, so the rendering becomes the same. 604 - create a clone of the on-screen renderaction to get the same 605 kind of custom rendering. 606 - check if we might be able to hook up the on-screen pre-render 607 callback to the offscreen renderer as well, if any point. 608 - disable accidentally enabled seek mode again (from typing 'osgrab'). 609 610 20050606 larsa. 611 */ 612 613 counter++; 614 if ( maxwidth <= 0 ) { 615 const char * env = 616 SoAny::si()->getenv("COIN_SOGRAB_GEOMETRY"); 617 if ( env ) { 618 sscanf(env, "%dx%d", &maxwidth, &maxheight); 619 } 620 if ( (maxwidth <= 0) || !env ) { 621 SbVec2s vp = PUBLIC(this)->getViewportRegion().getWindowSize(); 622 maxwidth = vp[0]; 623 maxheight = vp[1]; 624 } 625 } 626 627 if ( maxwidth <= 0 || maxheight <= 0 ) { 628 SoDebugError::post("So@Gui@RenderAreaP::offScreenGrab", 629 "invalid geometry: %dx%d", maxwidth, maxheight); 630 return; 631 } 632 SbVec2s vp = PUBLIC(this)->getViewportRegion().getWindowSize(); 633 634 const char * filenametpl = 635 SoAny::si()->getenv("COIN_SOGRAB_FILENAME"); 636 if ( !filenametpl ) filenametpl = fallback_name; 637 638 SbString filename; 639 filename.sprintf(filenametpl, counter); 640 const char * ext = strrchr(filename.getString(), '.'); 641 if ( !ext ) ext = fallback_ext; 642 ext++; 643 644 SbVec2s osvp(maxwidth, maxheight); 645 if ( vp[0] > maxwidth || vp[1] > maxheight || 646 (vp[0] < maxwidth && vp[1] < maxheight) ) { 647 float onscaspect = float(vp[0]) / float(vp[1]); 648 float offscaspect = float(maxwidth) / float(maxheight); 649 650 osvp[1] = maxheight; 651 osvp[0] = short(maxheight * onscaspect); 652 if ( osvp[0] > maxwidth ) { 653 osvp[0] = maxwidth; 654 osvp[1] = short(maxwidth * (1.0f / onscaspect)); 655 } 656 } 657 658 SoOffscreenRenderer os(osvp); 659 if ( !os.render(PUBLIC(this)->getSceneManager()->getSceneGraph()) ) { 660 return; 661 } 662 663 SbBool written = FALSE; 664 if (strcmp(ext, "rgb") == 0) { 665 written = os.writeToRGB(filename.getString()); 666 } 667 else { 668 written = os.writeToFile(filename, ext); 669 } 670 671 if (written) { 672 SoDebugError::postInfo("So@Gui@RenderAreaP::offScreenGrab", 673 "wrote image #%d, %dx%d as '%s'", 674 counter, osvp[0], osvp[1], 675 filename.getString()); 676 } 677 else { 678 SoDebugError::post("So@Gui@RenderAreaP::offScreenGrab", 679 "tried to write image '%s', but failed for unknown " 680 "reason", 681 filename.getString()); 682 } 683#endif // DEBUGGING_EGGS 684} 685 686int 687So@Gui@RenderAreaP::checkMagicSequences(const char c) 688{ 689#if DEBUGGING_EGGS 690 this->currentinput += c; 691 692 if (0) { // handy for debugging keyboard handling 693 SoDebugError::postInfo("So@Gui@RenderAreaP::checkMagicSequences", 694 "'%s'", this->currentinput.getString()); 695 } 696 697 const int cl = this->currentinput.getLength(); 698 699 static const char * keyseq[] = { 700 "glinfo", "ivinfo", "soinfo", "dumpiv", "cameras", "osgrab" 701 }; 702 static const int id[] = { 703 So@Gui@RenderAreaP::OPENGL, 704 So@Gui@RenderAreaP::INVENTOR, 705 So@Gui@RenderAreaP::TOOLKIT, 706 So@Gui@RenderAreaP::DUMPSCENEGRAPH, 707 So@Gui@RenderAreaP::DUMPCAMERAS, 708 So@Gui@RenderAreaP::OFFSCREENGRAB 709 }; 710 711 for (unsigned int i = 0; i < (sizeof(keyseq) / sizeof(keyseq[0])); i++) { 712 const int ml = strlen(keyseq[i]); 713 if (cl >= ml && this->currentinput.getSubString(cl - ml) == keyseq[i]) { 714 return id[i]; 715 } 716 } 717 718 // Limit memory usage. 719 if (cl > 1024) { this->currentinput = ""; } 720#endif // DEBUGGING_EGGS 721 722 return So@Gui@RenderAreaP::NONE; 723} 724 725// This method sets the window size data in all the connected device 726// classes. 727void 728So@Gui@RenderAreaP::setDevicesWindowSize(const SbVec2s size) 729{ 730 if (!this->devicelist) return; 731 const int num = this->devicelist->getLength(); 732 for (int i = 0; i < num; i++) 733 ((So@Gui@Device *)(*this->devicelist)[i])->setWindowSize(size); 734} 735 736// ************************************************************************* 737 738void 739So@Gui@RenderAreaP::renderCB(void * closure, SoSceneManager * manager) 740{ 741 assert(closure && manager); 742 So@Gui@RenderArea * thisptr = (So@Gui@RenderArea *) closure; 743 if (manager == PRIVATE(thisptr)->normalManager) { 744 thisptr->render(); 745 } else if (manager == PRIVATE(thisptr)->overlayManager) { 746 thisptr->renderOverlay(); 747 } else { 748#if SO@GUI@_DEBUG 749 SoDebugError::post("So@Gui@RenderAreaP::renderCB", 750 "invoked for unknown SoSceneManager (%p)", manager); 751#endif // SO@GUI@_DEBUG 752 return; 753 } 754} 755 756// Callback for automatic redraw on SoSelection changes. 757void 758So@Gui@RenderAreaP::selection_redraw_cb(void * closure, SoSelection * sel) 759{ 760 So@Gui@RenderArea * ra = (So@Gui@RenderArea *) closure; 761 if (sel == PRIVATE(ra)->normalselection) 762 ra->scheduleRedraw(); 763 else if (sel == PRIVATE(ra)->overlayselection) 764 ra->scheduleOverlayRedraw(); 765 else 766 assert(0 && "callback on unknown SoSelection node"); 767} 768 769// Private class constructor. 770So@Gui@RenderAreaP::So@Gui@RenderAreaP(So@Gui@RenderArea * api) 771{ 772 PUBLIC(this) = api; 773 774 this->normalManager = new SoSceneManager; 775 this->overlayManager = new SoSceneManager; 776 777 this->normalColormap = NULL; 778 this->normalColormapSize = 0; 779 this->overlayColormap = NULL; 780 this->overlayColormapSize = 0; 781 782 this->clear = TRUE; 783 this->clearZBuffer = TRUE; 784 this->clearOverlay = TRUE; 785 this->autoRedraw = TRUE; 786 787 this->normalselection = NULL; 788 this->overlayselection = NULL; 789 790 this->devices.mouse = NULL; 791 this->devices.keyboard = NULL; 792#ifdef HAVE_SPACENAV_SUPPORT 793 this->devices.spacenav = NULL; 794#endif // HAVE_SPACENAV_SUPPORT 795 796} 797 798// Private class destructor. 799So@Gui@RenderAreaP::~So@Gui@RenderAreaP() 800{ 801 delete this->normalManager; 802 delete this->overlayManager; 803 delete [] this->normalColormap; 804 delete [] this->overlayColormap; 805} 806 807// Common code for all constructors. 808void 809So@Gui@RenderAreaP::constructor(SbBool mouseInput, 810 SbBool keyboardInput, 811 SbBool build) 812{ 813 this->normalManager->setRenderCallback(So@Gui@RenderAreaP::renderCB, PUBLIC(this)); 814 this->normalManager->activate(); 815 this->overlayManager->setRenderCallback(So@Gui@RenderAreaP::renderCB, PUBLIC(this)); 816 this->overlayManager->activate(); 817 // FIXME: what is this magic number doing here - shouldn't we use 818 // SoGLCacheContextElement::getUniqueCacheContext() for Coin, and 819 // magic numbers just for SGI / TGS Inventor? 820 // 821 // On a side note: won't this code fail if we construct several 822 // So@Gui@RenderArea instances with overlays? They will all use 823 // cachecontext==1 for their SoGLRenderAction instances -- is that 824 // kosher? 825 // 826 // 20010831 mortene. 827 this->overlayManager->getGLRenderAction()->setCacheContext(1); 828 829 this->appeventhandler = NULL; 830 this->appeventhandlerdata = NULL; 831 832 this->devicelist = new SbPList; 833 834 if (mouseInput) { 835 this->devices.mouse = new So@Gui@Mouse; 836 PUBLIC(this)->registerDevice(this->devices.mouse); 837 } 838 839 if (keyboardInput) { 840 this->devices.keyboard = new So@Gui@Keyboard; 841 PUBLIC(this)->registerDevice(this->devices.keyboard); 842 } 843 844 if (! build) return; 845 PUBLIC(this)->setClassName("So@Gui@RenderArea"); 846 @WIDGET@ glarea = PUBLIC(this)->buildWidget(PUBLIC(this)->getParentWidget()); 847 PUBLIC(this)->setBaseWidget(glarea); 848 PUBLIC(this)->setSize(SbVec2s(400, 400)); 849} 850 851// This method invokes the application event handler, if one is set. 852SbBool 853So@Gui@RenderAreaP::invokeAppCB(@EVENT@ event) 854{ 855 if (this->appeventhandler != NULL) 856 return this->appeventhandler(this->appeventhandlerdata, event); 857 return FALSE; 858} 859 860// This method returns an SoEvent * corresponding to the given \a 861// event, or \c NULL if there are none. 862const SoEvent * 863So@Gui@RenderAreaP::getSoEvent(@EVENT@ event) 864{ 865 if (!this->devicelist) 866 return (SoEvent *) NULL; 867 868 const SoEvent * soevent = NULL; 869 const int num = this->devicelist->getLength(); 870 for (int i = 0; (i < num) && (soevent == NULL); i++) 871 soevent = ((So@Gui@Device *)(*this->devicelist)[i])->translateEvent(event); 872 873 return soevent; 874} 875 876#endif // DOXYGEN_SKIP_THIS 877 878// ************************************************************************* 879 880/*! 881 Public constructor. 882*/ 883So@Gui@RenderArea::So@Gui@RenderArea(@WIDGET@ parent, 884 const char * name, 885 SbBool embed, 886 SbBool mouseInput, 887 SbBool keyboardInput) 888 : inherited(parent, name, embed, So@Gui@RenderAreaP::GL_DEFAULT_MODE, FALSE) 889{ 890 PRIVATE(this) = new So@Gui@RenderAreaP(this); 891 PRIVATE(this)->constructor(mouseInput, keyboardInput, TRUE); 892} 893 894/*! 895 Protected constructor used by derived classes. 896*/ 897So@Gui@RenderArea::So@Gui@RenderArea(@WIDGET@ parent, 898 const char * name, 899 SbBool embed, 900 SbBool mouseInput, 901 SbBool keyboardInput, 902 SbBool build) 903 : inherited(parent, name, embed, So@Gui@RenderAreaP::GL_DEFAULT_MODE, FALSE) 904{ 905 PRIVATE(this) = new So@Gui@RenderAreaP(this); 906 PRIVATE(this)->constructor(mouseInput, keyboardInput, build); 907} 908 909/*! 910 Destructor. 911*/ 912So@Gui@RenderArea::~So@Gui@RenderArea() 913{ 914 // Clean out any callbacks we may have registered with SoSelection 915 // nodes. 916 this->redrawOverlayOnSelectionChange(NULL); 917 this->redrawOnSelectionChange(NULL); 918 919 for (int i = PRIVATE(this)->devicelist->getLength() - 1; i >= 0; i--) { 920 So@Gui@Device * device = (So@Gui@Device *) ((*PRIVATE(this)->devicelist)[i]); 921 this->unregisterDevice(device); 922 delete device; 923 } 924 delete PRIVATE(this)->devicelist; 925 delete PRIVATE(this); 926} 927 928// ************************************************************************* 929 930/*! 931 This method adds \a device to the list of devices handling events 932 for this component. 933*/ 934void 935So@Gui@RenderArea::registerDevice(So@Gui@Device * device) 936{ 937 int idx = PRIVATE(this)->devicelist->find(device); 938 if (idx != -1) { 939#if SO@GUI@_DEBUG 940 SoDebugError::postWarning("So@Gui@RenderArea::registerDevice", 941 "device already registered"); 942#endif // SO@GUI@_DEBUG 943 return; 944 } 945 946 PRIVATE(this)->devicelist->append(device); 947 @WIDGET@ w = this->getGLWidget(); 948 if (w != NULL) { 949#ifdef __COIN_SOXT__ 950 device->enable(w, (SoXtEventHandler *) &So@Gui@GLWidget::eventHandler, (void *)this); 951#else 952 device->enable(w, &So@Gui@GLWidgetP::eventHandler, (void *)this); 953#endif 954 device->setWindowSize(this->getGLSize()); 955 } 956} 957 958/*! 959 This method removes \a device from the list of devices handling 960 events for this component. 961*/ 962void 963So@Gui@RenderArea::unregisterDevice(So@Gui@Device * device) 964{ 965 assert(PRIVATE(this)->devicelist != NULL); 966 const int idx = PRIVATE(this)->devicelist->find(device); 967 if (idx == -1) { 968#if SO@GUI@_DEBUG 969 SoDebugError::post("So@Gui@RenderArea::unregisterDevice", 970 "tried to remove nonexisting device"); 971#endif // SO@GUI@_DEBUG 972 return; 973 } 974 975 PRIVATE(this)->devicelist->remove(idx); 976 @WIDGET@ w = this->getGLWidget(); 977 if (w != NULL) { device->disable(w, NULL, NULL); } 978} 979 980// ************************************************************************* 981 982// Documented in superclass. 983void 984So@Gui@RenderArea::afterRealizeHook(void) 985{ 986 inherited::afterRealizeHook(); 987 988#ifdef HAVE_JOYSTICK_LINUX 989 if (So@Gui@LinuxJoystick::exists()) 990 this->registerDevice(new So@Gui@LinuxJoystick); 991#endif // HAVE_JOYSTICK_LINUX 992 993#ifdef HAVE_SPACENAV_SUPPORT 994 PRIVATE(this)->devices.spacenav = new So@Gui@SpacenavDevice; 995 this->registerDevice(PRIVATE(this)->devices.spacenav); 996#endif // HAVE_SPACENAV_SUPPORT 997} 998 999/*! 1000 This method sets the scene graph to be rendered in the normal bitmap 1001 planes. 1002 1003 \sa getSceneGraph(), setOverlaySceneGraph() 1004*/ 1005void 1006So@Gui@RenderArea::setSceneGraph(SoNode * scene) 1007{ 1008 PRIVATE(this)->normalManager->setSceneGraph(scene); 1009} 1010 1011/*! 1012 This method returns a reference to the scene graph root node as set 1013 by the user. 1014 1015 \sa So@Gui@RenderArea::getSceneManager() 1016*/ 1017SoNode * 1018So@Gui@RenderArea::getSceneGraph(void) 1019{ 1020 return PRIVATE(this)->normalManager->getSceneGraph(); 1021} 1022 1023/*! 1024 This method sets the scene graph to render for the overlay bitmap 1025 planes. 1026 1027 It will automatically take care of setting up overplay planes in the 1028 OpenGL canvas if the OpenGL hardware and driver supports it. 1029 1030 Important note: not all graphics hardware and / or drivers for 1031 graphics hardware support overlay planes, so application programmers 1032 are adviced to find some other way of accomplishing what they want 1033 to do before resorting to using overlay planes. Using overlay 1034 planes will in practice severely limit the portability of 1035 applications which depend on them being available. 1036 1037 \sa setSceneGraph(), getOverlaySceneGraph() 1038*/ 1039void 1040So@Gui@RenderArea::setOverlaySceneGraph(SoNode * scene) 1041{ 1042 SoNode * oldroot = this->getOverlaySceneGraph(); 1043 PRIVATE(this)->overlayManager->setSceneGraph(scene); 1044 1045 if (!oldroot && scene) { this->setOverlayRender(TRUE); } 1046 else if (oldroot && !scene) { this->setOverlayRender(FALSE); } 1047} 1048 1049/*! 1050 This method returns the scene graph for the overlay scene. 1051*/ 1052SoNode * 1053So@Gui@RenderArea::getOverlaySceneGraph(void) 1054{ 1055 return PRIVATE(this)->overlayManager->getSceneGraph(); 1056} 1057 1058// ************************************************************************* 1059 1060/*! 1061 This method sets the background color of the scene. 1062*/ 1063void 1064So@Gui@RenderArea::setBackgroundColor(const SbColor & color) 1065{ 1066 assert(PRIVATE(this)->normalManager != NULL); 1067 PRIVATE(this)->normalManager->setBackgroundColor(color); 1068 this->scheduleRedraw(); 1069} 1070 1071/*! 1072 This method returns the background color for the scene. 1073*/ 1074const SbColor & 1075So@Gui@RenderArea::getBackgroundColor(void) const 1076{ 1077 assert(PRIVATE(this)->normalManager != NULL); 1078#if HAVE_SBCOLOR4F_GETBACKGROUNDCOLOR 1079 SbColor4f bgcol = PRIVATE(this)->normalManager->getBackgroundColor(); 1080 return SbColor(bgcol[0], bgcol[1], bgcol[2]); 1081#else 1082 return PRIVATE(this)->normalManager->getBackgroundColor(); 1083#endif 1084} 1085 1086// ************************************************************************* 1087 1088/*! 1089 This method sets the index of the background color for the scene. 1090*/ 1091void 1092So@Gui@RenderArea::setBackgroundIndex(int idx) 1093{ 1094 assert(PRIVATE(this)->normalManager != NULL); 1095 PRIVATE(this)->normalManager->setBackgroundIndex(idx); 1096 this->scheduleRedraw(); 1097} 1098 1099/*! 1100 This method returns the index of the background color for the scene. 1101*/ 1102int 1103So@Gui@RenderArea::getBackgroundIndex(void) const 1104{ 1105 assert(PRIVATE(this)->normalManager != NULL); 1106 return PRIVATE(this)->normalManager->getBackgroundIndex(); 1107} 1108 1109// ************************************************************************* 1110 1111/*! 1112 This method sets the index of the background for the overlay scene. 1113*/ 1114void 1115So@Gui@RenderArea::setOverlayBackgroundIndex(int idx) 1116{ 1117 assert(PRIVATE(this)->overlayManager != NULL); 1118 PRIVATE(this)->overlayManager->setBackgroundIndex(idx); 1119 this->scheduleOverlayRedraw(); 1120} 1121 1122/*! 1123 This method returns the index of the background for the overlay scene. 1124*/ 1125int 1126So@Gui@RenderArea::getOverlayBackgroundIndex(void) const 1127{ 1128 assert(PRIVATE(this)->overlayManager != NULL); 1129 return PRIVATE(this)->overlayManager->getBackgroundIndex(); 1130} 1131 1132// ************************************************************************* 1133 1134/*! 1135 This method sets the colormap for the scene. 1136*/ 1137void 1138So@Gui@RenderArea::setColorMap(int start, int num, const SbColor * colors) 1139{ 1140 delete [] PRIVATE(this)->normalColormap; 1141 PRIVATE(this)->normalColormapStart = start; 1142 PRIVATE(this)->normalColormapSize = num; 1143 PRIVATE(this)->normalColormap = new SbColor [ num ]; 1144 for (int i = 0; i < num; i++) 1145 PRIVATE(this)->normalColormap[i] = colors[i]; 1146 this->scheduleRedraw(); 1147} 1148 1149/*! 1150 This method sets the colormap for the overlay scene. 1151*/ 1152void 1153So@Gui@RenderArea::setOverlayColorMap(int start, int num, 1154 const SbColor * colors) 1155{ 1156 delete [] PRIVATE(this)->overlayColormap; 1157 PRIVATE(this)->overlayColormapStart = start; 1158 PRIVATE(this)->overlayColormapSize = num; 1159 PRIVATE(this)->overlayColormap = new SbColor [ num ]; 1160 for (int i = 0; i < num; i++) { 1161 PRIVATE(this)->overlayColormap[i] = colors[i]; 1162 } 1163 this->scheduleOverlayRedraw(); 1164} 1165 1166// ************************************************************************* 1167 1168/*! 1169 This method sets the viewport region. 1170*/ 1171void 1172So@Gui@RenderArea::setViewportRegion(const SbViewportRegion & region) 1173{ 1174 if (region.getWindowSize()[0] == -1) return; 1175 1176#if SO@GUI@_DEBUG && 0 // debug 1177 SoDebugError::postInfo("So@Gui@RenderArea::setViewportRegion", 1178 "size=<%d, %d>", 1179 region.getWindowSize()[0], 1180 region.getWindowSize()[1]); 1181#endif // debug 1182 1183 PRIVATE(this)->normalManager->setViewportRegion(region); 1184 PRIVATE(this)->overlayManager->setViewportRegion(region); 1185 this->scheduleRedraw(); 1186} 1187 1188/*! 1189 This method returns the viewport region. 1190*/ 1191const SbViewportRegion & 1192So@Gui@RenderArea::getViewportRegion(void) const 1193{ 1194 assert(PRIVATE(this)->normalManager != NULL); 1195 return PRIVATE(this)->normalManager->getGLRenderAction()->getViewportRegion(); 1196} 1197 1198// ************************************************************************* 1199 1200/*! 1201 This method sets the transparency type to be used for the scene. 1202*/ 1203void 1204So@Gui@RenderArea::setTransparencyType(SoGLRenderAction::TransparencyType type) 1205{ 1206 assert(PRIVATE(this)->normalManager != NULL); 1207 PRIVATE(this)->normalManager->getGLRenderAction()->setTransparencyType(type); 1208 PRIVATE(this)->overlayManager->getGLRenderAction()->setTransparencyType(type); 1209 this->scheduleRedraw(); 1210} 1211 1212/*! 1213 This method returns the transparency type used for the scene. 1214*/ 1215SoGLRenderAction::TransparencyType 1216So@Gui@RenderArea::getTransparencyType(void) const 1217{ 1218 assert(PRIVATE(this)->normalManager != NULL); 1219 return PRIVATE(this)->normalManager->getGLRenderAction()->getTransparencyType(); 1220} 1221 1222// ************************************************************************* 1223 1224/*! 1225 This method sets the antialiasing used for the scene. 1226 1227 The \a smoothing flag signifies whether or not line and point 1228 aliasing should be turned on. See documentation of 1229 SoGLRenderAction::setSmoothing(), which will be called from this 1230 function. 1231 1232 \a numPasses gives the number of re-renderings to do of the scene, 1233 blending together the results from slight "jitters" of the camera 1234 view, into the OpenGL accumulation buffer. For further information, 1235 see documentation of SoGLRenderAction::setNumPasses() and 1236 So@Gui@GLWidget::setAccumulationBuffer(). 1237*/ 1238void 1239So@Gui@RenderArea::setAntialiasing(SbBool smoothing, int numPasses) 1240{ 1241 // FIXME: is this really necessary? I think we should either ignore 1242 // the call or store values for later migration if the scenemanager 1243 // instance(s) haven't been made yet. 20010331 mortene. 1244 assert(PRIVATE(this)->normalManager != NULL); 1245 1246 // Instead of piping the call further to 1247 // SoSceneManager::setAntialiasing(), we duplicate the code found in 1248 // that function. The reason for this is that we want to work around 1249 // a bug found in SGI Inventor, where they define the 1250 // setAntialiasing() method, but doesn't actually implement it. So 1251 // we don't use it to avoid a linker error for those compiling So* 1252 // libraries on top of the older SGI Inventor versions with this 1253 // bug. 1254 // 1255 // We should perhaps throw in a configure check for the 1256 // SoSceneManager::setAntialiasing() method and only activate this 1257 // code when actually needed? 1258 // mortene@sim.no 1259 enum { MGRS = 2 }; 1260 SoSceneManager * mgrs[MGRS] = { PRIVATE(this)->normalManager, 1261 PRIVATE(this)->overlayManager }; 1262 for (int i=0; i < MGRS; i++) { 1263 SoGLRenderAction * glra = mgrs[i]->getGLRenderAction(); 1264 if (glra) { 1265 glra->setSmoothing(smoothing); 1266 glra->setNumPasses(numPasses); 1267 } 1268 } 1269 1270 this->scheduleRedraw(); 1271} 1272 1273/*! 1274 This method returns the antialiasing used for the scene. 1275*/ 1276void 1277So@Gui@RenderArea::getAntialiasing(SbBool & smoothing, int & numPasses) const 1278{ 1279 // FIXME: there's an API design flaw here, as it is assumed that the 1280 // antialiasing setting for the renderaction in the "normal" 1281 // rendering context always matches what is the case for the 1282 // renderaction in the overlay manager. This is not necessarily 1283 // true. Could be solved by an additional argument to 1284 // getAntialiasing(): a boolean indicator on whether or not we want 1285 // the overlay context with a default value (false) to keep API 1286 // compatibility. 20010331 mortene. 1287 1288 assert(PRIVATE(this)->normalManager != NULL); 1289 1290 // About why we don't use SoSceneManager::getAntialiasing() 1291 // directly, see comment in SoGuiRenderArea::setAntiAliasing(). 1292 SoGLRenderAction * glra = PRIVATE(this)->normalManager->getGLRenderAction(); 1293 smoothing = glra->isSmoothing(); 1294 numPasses = glra->getNumPasses(); 1295} 1296 1297/*! 1298 This method sets whether the render buffer should be cleared before 1299 rendering. 1300 1301 The first argument specifies whether or not to clear out the pixels 1302 in the buffer, the second argument specifies whether or not the 1303 z-buffer values should be cleared between renderings. 1304 1305 Setting the first argument to \c FALSE can for instance be used when 1306 you want to clear out the buffer yourself, for instance by drawing a 1307 background image "under" the 3D scene rendered by Coin / Inventor. 1308*/ 1309void 1310So@Gui@RenderArea::setClearBeforeRender(SbBool enable, SbBool zbEnable) 1311{ 1312 PRIVATE(this)->clear = enable; 1313 PRIVATE(this)->clearZBuffer = zbEnable; 1314 1315 this->scheduleRedraw(); 1316} 1317 1318/*! 1319 This method returns whether the render buffer is cleared before each 1320 render. 1321*/ 1322SbBool 1323So@Gui@RenderArea::isClearBeforeRender(void) const 1324{ 1325 return PRIVATE(this)->clear; 1326} 1327 1328/*! 1329 This method returns whether the render buffer's Z buffer is cleared 1330 before each render. 1331*/ 1332SbBool 1333So@Gui@RenderArea::isClearZBufferBeforeRender(void) const 1334{ 1335 return PRIVATE(this)->clearZBuffer; 1336} 1337 1338/*! 1339 This method sets whether the overlay render buffer should be cleared 1340 before each render or not. 1341*/ 1342void 1343So@Gui@RenderArea::setClearBeforeOverlayRender(SbBool enable) 1344{ 1345 PRIVATE(this)->clearOverlay = enable; 1346 this->scheduleOverlayRedraw(); 1347} 1348 1349/*! 1350 This method returns whether the overlay render buffer is cleared 1351 before each redraw or not. 1352*/ 1353SbBool 1354So@Gui@RenderArea::isClearBeforeOverlayRender(void) const 1355{ 1356 return PRIVATE(this)->clearOverlay; 1357} 1358 1359/*! 1360 This method sets whether redrawing should be handled automatically 1361 or not when data in the scenegraph changes. 1362 1363 The default setting causes the renderarea to automatically trigger a 1364 redraw of the scenegraph contents. 1365*/ 1366void 1367So@Gui@RenderArea::setAutoRedraw(SbBool enable) 1368{ 1369 if (enable) { 1370 PRIVATE(this)->normalManager->activate(); 1371 PRIVATE(this)->overlayManager->activate(); 1372 } 1373 else { 1374 PRIVATE(this)->normalManager->deactivate(); 1375 PRIVATE(this)->overlayManager->deactivate(); 1376 } 1377 PRIVATE(this)->autoRedraw = enable; 1378} 1379 1380/*! 1381 This method returns whether redrawing is handled automatically 1382 not. 1383*/ 1384SbBool 1385So@Gui@RenderArea::isAutoRedraw(void) const 1386{ 1387 return PRIVATE(this)->autoRedraw; 1388} 1389 1390/*! 1391 This method sets the redraw priority. 1392*/ 1393void 1394So@Gui@RenderArea::setRedrawPriority(uint32_t priority) 1395{ 1396 PRIVATE(this)->normalManager->setRedrawPriority(priority); 1397 PRIVATE(this)->overlayManager->setRedrawPriority(priority); 1398} 1399 1400/*! 1401 This method returns the redraw priority. 1402*/ 1403uint32_t 1404So@Gui@RenderArea::getRedrawPriority(void) const 1405{ 1406 assert(PRIVATE(this)->normalManager != NULL); 1407 return PRIVATE(this)->normalManager->getRedrawPriority(); 1408} 1409 1410/*! 1411 This function returns the default redraw priority. 1412*/ 1413uint32_t 1414So@Gui@RenderArea::getDefaultRedrawPriority(void) 1415{ 1416 return SoSceneManager::getDefaultRedrawPriority(); 1417} 1418 1419/*! 1420 This method causes the immediate rendering of the scene, by calling 1421 So@Gui@RenderArea::redraw(). 1422*/ 1423void 1424So@Gui@RenderArea::render(void) 1425{ 1426 this->redraw(); 1427} 1428 1429/*! 1430 This method renders the overlay scene. 1431*/ 1432void 1433So@Gui@RenderArea::renderOverlay(void) 1434{ 1435 this->redrawOverlay(); 1436} 1437 1438/*! 1439 This method schedules a redraw to happen at a later time (when the 1440 application has processed it's other events first). 1441*/ 1442void 1443So@Gui@RenderArea::scheduleRedraw(void) 1444{ 1445#if SO@GUI@_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug 1446 SoDebugError::postInfo("So@Gui@RenderArea::scheduleRedraw", 1447 "invoked"); 1448#endif // debug 1449 1450 assert(PRIVATE(this)->normalManager != NULL); 1451 PRIVATE(this)->normalManager->scheduleRedraw(); // Redraw when idle. 1452} 1453 1454/*! 1455 This method schedules a redraw of the overlay scene. 1456*/ 1457void 1458So@Gui@RenderArea::scheduleOverlayRedraw(void) 1459{ 1460 assert(PRIVATE(this)->overlayManager != NULL); 1461 PRIVATE(this)->overlayManager->scheduleRedraw(); // Redraw when idle. 1462} 1463 1464#ifndef DOXYGEN_SKIP_THIS 1465void 1466So@Gui@RenderAreaP::replaceSoSelectionMonitor(SoSelection * newsel, 1467 SoSelection * oldsel) const 1468{ 1469 if (newsel) { newsel->ref(); } 1470 1471 if (oldsel) { 1472 oldsel->removeChangeCallback(So@Gui@RenderAreaP::selection_redraw_cb, 1473 PUBLIC(this)); 1474 oldsel->unref(); 1475 } 1476 1477 if (newsel) { 1478 newsel->addChangeCallback(So@Gui@RenderAreaP::selection_redraw_cb, 1479 PUBLIC(this)); 1480 } 1481} 1482#endif // DOXYGEN_SKIP_THIS 1483 1484// FIXME: the interface below is badly designed, see the comment in 1485// the function documentation. 20001002 mortene. 1486 1487/*! 1488 Do automatic redraw of the scenegraph when a selection under the 1489 SoSelection node is changed. 1490 1491 Pass \c NULL to deactivate. 1492 1493 (Only one SoSelection node can be monitored at any given time. This 1494 is obviously a rather silly design flaw. We choose to match the 1495 original Inventor API here, but this will probably change in the 1496 next major revision of the library.) 1497*/ 1498void 1499So@Gui@RenderArea::redrawOnSelectionChange(SoSelection * selection) 1500{ 1501 PRIVATE(this)->replaceSoSelectionMonitor(selection, PRIVATE(this)->normalselection); 1502 PRIVATE(this)->normalselection = selection; 1503} 1504 1505/*! 1506 Do automatic redraw of the scenegraph in the overlay planes when a 1507 selection under the SoSelection node is changed. 1508 1509 Pass \c NULL to deactivate. 1510 1511 \sa So@Gui@RenderArea::redrawOnSelectionChange() 1512*/ 1513void 1514So@Gui@RenderArea::redrawOverlayOnSelectionChange(SoSelection * selection) 1515{ 1516 PRIVATE(this)->replaceSoSelectionMonitor(selection, PRIVATE(this)->overlayselection); 1517 PRIVATE(this)->overlayselection = selection; 1518} 1519 1520/*! 1521 This method sets the render area event callback. 1522*/ 1523void 1524So@Gui@RenderArea::setEventCallback(So@Gui@RenderAreaEventCB * func, 1525 void * user) 1526{ 1527 PRIVATE(this)->appeventhandler = func; 1528 PRIVATE(this)->appeventhandlerdata = user; 1529} 1530 1531/*! 1532 This method sets the normal scene SoSceneManager object. 1533 1534 The previous set scene manager is deleted, and there is no way to 1535 currently avoid that. This might change in the future. 1536*/ 1537void 1538So@Gui@RenderArea::setSceneManager(SoSceneManager * manager) 1539{ 1540 assert(PRIVATE(this)->normalManager != NULL); 1541 PRIVATE(this)->normalManager->setRenderCallback(NULL, NULL); 1542 1543 // NOTE: Although deleting the previous scene manager here is correct 1544 // behaviour from a compatibility-POV, I think it is ugly and should 1545 // be addressed in some other way if possible. It is also inconsistent 1546 // with overlay scenemanager management. 20061015 larsa 1547 delete PRIVATE(this)->normalManager; 1548 1549 PRIVATE(this)->normalManager = manager; 1550 if (PRIVATE(this)->normalManager) { 1551 PRIVATE(this)->normalManager->setSize(this->getGLSize()); 1552 } 1553} 1554 1555/*! 1556 This method returns the normal scene SoSceneManager object. 1557 1558 Having a reference to the SoSceneManager instance is useful for 1559 getting at the \e real root node of the rendering scenegraph, 1560 including camera, headlight and miscellaneous drawstyle nodes. The 1561 getSceneGraph() method will only return the \e user scenegrah for 1562 So@Gui@RenderArea subclass So@Gui@Viewer and further subclasses. The 1563 reason this is not always what you want is because certain actions 1564 (like the SoRayPickAction) needs to traverse a valid camera if it 1565 should work as expected. 1566 1567 If you need to get a pointer to the \e real root node use this 1568 method to get the SoSceneManager instance reference used by the 1569 So@Gui@RenderArea, then use SoSceneManager::getSceneGraph() to get 1570 the root node Coin uses for rendering. 1571*/ 1572SoSceneManager * 1573So@Gui@RenderArea::getSceneManager(void) const 1574{ 1575 return PRIVATE(this)->normalManager; 1576} 1577 1578/*! 1579 This method sets the overlay scene SoSceneManager object. 1580 1581 The previous set scene manager is not freed and will leak unless 1582 the user frees it. 1583*/ 1584void 1585So@Gui@RenderArea::setOverlaySceneManager(SoSceneManager * manager) 1586{ 1587 PRIVATE(this)->overlayManager = manager; 1588 if (PRIVATE(this)->overlayManager) { 1589 PRIVATE(this)->overlayManager->setSize(this->getGLSize()); 1590 } 1591} 1592 1593/*! 1594 This method returns the overlay scene SoSceneManager object. 1595*/ 1596SoSceneManager * 1597So@Gui@RenderArea::getOverlaySceneManager(void) const 1598{ 1599 return PRIVATE(this)->overlayManager; 1600} 1601 1602/*! 1603 This method sets the SoGLRenderAction object for the normal scene. 1604*/ 1605void 1606So@Gui@RenderArea::setGLRenderAction(SoGLRenderAction * action) 1607{ 1608 assert(PRIVATE(this)->normalManager != NULL); 1609 PRIVATE(this)->normalManager->setGLRenderAction(action); 1610 // Force an update of the SoGLRenderAction to the correct 1611 // updatearea, aspectratio, etc. 1612 this->sizeChanged(this->getSize()); 1613} 1614 1615/*! 1616 This method returns the SoGLRenderAction object for the normal scene. 1617*/ 1618SoGLRenderAction * 1619So@Gui@RenderArea::getGLRenderAction(void) const 1620{ 1621 assert(PRIVATE(this)->normalManager != NULL); 1622 return PRIVATE(this)->normalManager->getGLRenderAction(); 1623} 1624 1625/*! 1626 This method sets the SoGLRenderAction object for rendering the 1627 overlay scenegraph. 1628*/ 1629void 1630So@Gui@RenderArea::setOverlayGLRenderAction(SoGLRenderAction * action) 1631{ 1632 assert(PRIVATE(this)->overlayManager != NULL); 1633 PRIVATE(this)->overlayManager->setGLRenderAction(action); 1634} 1635 1636/*! 1637 This method returns the SoGLRenderAction object for the overlay scene 1638 graph. 1639*/ 1640SoGLRenderAction * 1641So@Gui@RenderArea::getOverlayGLRenderAction(void) const 1642{ 1643 assert(PRIVATE(this)->overlayManager != NULL); 1644 return PRIVATE(this)->overlayManager->getGLRenderAction(); 1645} 1646 1647/*! 1648 This method is called from the render() method and takes care of 1649 setting up the context for OpenGL rendering (by making the OpenGL 1650 canvas the current context and specifying either the front or back 1651 buffer for rendering, depending on whether we're in singlebuffer or 1652 doublebuffer mode). 1653 1654 After setting up the OpenGL context, it calls actualRedraw() for the 1655 actual scenegraph rendering to take place. 1656 1657 Finally, the OpenGL buffers are either swapped back-to-front (for 1658 doublebuffering) or flushed (for singlebuffering), and our OpenGL 1659 context is unlocked. 1660 1661 The application programmer may override this method if extreme 1662 low-level control of the rendering process is necessary. Usually, 1663 you should be able to get away with overriding actualRedraw() for 1664 special cases, though. 1665*/ 1666void 1667So@Gui@RenderArea::redraw(void) 1668{ 1669#if SO@GUI@_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug 1670 SoDebugError::postInfo("So@Gui@RenderArea::redraw", 1671 "start (isVisible=%s waitForExpose=%s)", 1672 this->isVisible() ? "TRUE" : "FALSE", 1673 this->waitForExpose ? "TRUE" : "FALSE"); 1674#endif // debug 1675 1676 if (! this->isVisible() || !this->hasNormalGLArea() || this->waitForExpose) 1677 return; 1678 this->glLockNormal(); // this makes the GL context "current" 1679 1680 SbBool drawfront = 1681 ! this->isDoubleBuffer() || 1682 this->isDrawToFrontBufferEnable(); 1683 1684 glDrawBuffer(drawfront ? GL_FRONT : GL_BACK); 1685 1686 this->actualRedraw(); 1687 1688 if (!drawfront) { this->glSwapBuffers(); } 1689 else { this->glFlushBuffer(); } 1690 this->glUnlockNormal(); 1691 1692#if SO@GUI@_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug 1693 SoDebugError::postInfo("So@Gui@RenderArea::render", "done"); 1694#endif // debug 1695} 1696 1697// Note: the following function documentation block will also be used 1698// for all the miscellaneous viewer subclasses, so keep it general. 1699/*! 1700 This method instantly redraws the normal (non-overlay) scenegraph by 1701 calling SoSceneManager::render(). 1702 1703 Subclasses may override this method to add their own rendering 1704 before or after Coin renders it's scenegraph. 1705 1706 The following is a complete example that demonstrates one way of 1707 adding both a background image and foreground (overlay) geometry to 1708 the "normal" rendering: 1709 1710 \code 1711 // This example shows how to put a permanent background image on 1712 // your viewer canvas, below the 3D graphics, plus overlay 1713 // foreground geometry. Written by mortene. 1714 // Copyright Kongsberg Oil & Gas Technologies 2002. 1715 1716 // ************************************************************************* 1717 1718 #include <Inventor/@Gui@/So@Gui@.h> 1719 #include <Inventor/@Gui@/viewers/So@Gui@ExaminerViewer.h> 1720 #include <Inventor/nodes/SoBaseColor.h> 1721 #include <Inventor/nodes/SoCone.h> 1722 #include <Inventor/nodes/SoCube.h> 1723 #include <Inventor/nodes/SoImage.h> 1724 #include <Inventor/nodes/SoLightModel.h> 1725 #include <Inventor/nodes/SoOrthographicCamera.h> 1726 #include <Inventor/nodes/SoRotationXYZ.h> 1727 #include <Inventor/nodes/SoSeparator.h> 1728 #include <Inventor/nodes/SoTranslation.h> 1729 1730 #include <GL/gl.h> 1731 1732 // ************************************************************************* 1733 1734 class MyExaminerViewer : public So@Gui@ExaminerViewer { 1735 1736 public: 1737 MyExaminerViewer(@WIDGET@ parent, const char * filename); 1738 ~MyExaminerViewer(); 1739 1740 protected: 1741 virtual void actualRedraw(void); 1742 1743 private: 1744 SoSeparator * bckgroundroot; 1745 SoSeparator * foregroundroot; 1746 SoRotationXYZ * arrowrotation; 1747 }; 1748 1749 MyExaminerViewer::MyExaminerViewer(@WIDGET@ parent, const char * filename) 1750 : So@Gui@ExaminerViewer(parent) 1751 { 1752 // Coin should not clear the pixel-buffer, so the background image 1753 // is not removed. 1754 this->setClearBeforeRender(FALSE, TRUE); 1755 1756 1757 // Set up background scenegraph with image in it. 1758 1759 this->bckgroundroot = new SoSeparator; 1760 this->bckgroundroot->ref(); 1761 1762 SoOrthographicCamera * cam = new SoOrthographicCamera; 1763 cam->position = SbVec3f(0, 0, 1); 1764 cam->height = 1; 1765 // SoImage will be at z==0.0. 1766 cam->nearDistance = 0.5; 1767 cam->farDistance = 1.5; 1768 1769 SoImage * img = new SoImage; 1770 img->vertAlignment = SoImage::HALF; 1771 img->horAlignment = SoImage::CENTER; 1772 img->filename = filename; 1773 1774 this->bckgroundroot->addChild(cam); 1775 this->bckgroundroot->addChild(img); 1776 1777 // Set up foreground, overlayed scenegraph. 1778 1779 this->foregroundroot = new SoSeparator; 1780 this->foregroundroot->ref(); 1781 1782 SoLightModel * lm = new SoLightModel; 1783 lm->model = SoLightModel::BASE_COLOR; 1784 1785 SoBaseColor * bc = new SoBaseColor; 1786 bc->rgb = SbColor(1, 1, 0); 1787 1788 cam = new SoOrthographicCamera; 1789 cam->position = SbVec3f(0, 0, 5); 1790 cam->height = 10; 1791 cam->nearDistance = 0; 1792 cam->farDistance = 10; 1793 1794 const double ARROWSIZE = 2.0; 1795 1796 SoTranslation * posit = new SoTranslation; 1797 posit->translation = SbVec3f(-2.5 * ARROWSIZE, 1.5 * ARROWSIZE, 0); 1798 1799 arrowrotation = new SoRotationXYZ; 1800 arrowrotation->axis = SoRotationXYZ::Z; 1801 1802 SoTranslation * offset = new SoTranslation; 1803 offset->translation = SbVec3f(ARROWSIZE/2.0, 0, 0); 1804 1805 SoCube * cube = new SoCube; 1806 cube->width = ARROWSIZE; 1807 cube->height = ARROWSIZE/15.0; 1808 1809 this->foregroundroot->addChild(cam); 1810 this->foregroundroot->addChild(lm); 1811 this->foregroundroot->addChild(bc); 1812 this->foregroundroot->addChild(posit); 1813 this->foregroundroot->addChild(arrowrotation); 1814 this->foregroundroot->addChild(offset); 1815 this->foregroundroot->addChild(cube); 1816 } 1817 1818 MyExaminerViewer::~MyExaminerViewer() 1819 { 1820 this->bckgroundroot->unref(); 1821 this->foregroundroot->unref(); 1822 } 1823 1824 void 1825 MyExaminerViewer::actualRedraw(void) 1826 { 1827 // Must set up the OpenGL viewport manually, as upon resize 1828 // operations, Coin won't set it up until the SoGLRenderAction is 1829 // applied again. And since we need to do glClear() before applying 1830 // the action.. 1831 const SbViewportRegion vp = this->getViewportRegion(); 1832 SbVec2s origin = vp.getViewportOriginPixels(); 1833 SbVec2s size = vp.getViewportSizePixels(); 1834 glViewport(origin[0], origin[1], size[0], size[1]); 1835 1836 const SbColor col = this->getBackgroundColor(); 1837 glClearColor(col[0], col[1], col[2], 0.0f); 1838 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1839 1840 // Render our scenegraph with the image. 1841 SoGLRenderAction * glra = this->getGLRenderAction(); 1842 glra->apply(this->bckgroundroot); 1843 1844 1845 // Render normal scenegraph. 1846 So@Gui@ExaminerViewer::actualRedraw(); 1847 1848 1849 // Increase arrow angle with 1/1000 � every frame. 1850 arrowrotation->angle = arrowrotation->angle.getValue() + (0.001 / M_PI * 180); 1851 // Render overlay front scenegraph. 1852 glClear(GL_DEPTH_BUFFER_BIT); 1853 glra->apply(this->foregroundroot); 1854 } 1855 1856 // ************************************************************************* 1857 1858 int 1859 main(int argc, char ** argv) 1860 { 1861 if (argc != 2) { 1862 (void)fprintf(stderr, "\n\n\tUsage: %s <image-filename>\n\n", argv[0]); 1863 exit(1); 1864 } 1865 1866 @WIDGET@ window = So@Gui@::init(argv[0]); 1867 1868 MyExaminerViewer * viewer = new MyExaminerViewer(window, argv[1]); 1869 1870 viewer->setSceneGraph(new SoCone); 1871 viewer->show(); 1872 1873 So@Gui@::show(window); 1874 So@Gui@::mainLoop(); 1875 1876 delete viewer; 1877 return 0; 1878 } 1879 1880 // ************************************************************************* 1881 \endcode 1882*/ 1883void 1884So@Gui@RenderArea::actualRedraw(void) 1885{ 1886 assert(PRIVATE(this)->normalManager != NULL); 1887 if ( !this->isVisible() ) return; 1888 PRIVATE(this)->normalManager->render(PRIVATE(this)->clear, PRIVATE(this)->clearZBuffer); 1889} 1890 1891/*! 1892 This method redraws the overlay scene. 1893*/ 1894void 1895So@Gui@RenderArea::redrawOverlay(void) 1896{ 1897 if (!this->isVisible() || this->waitForExpose || !this->hasOverlayGLArea()) { 1898 return; 1899 } 1900 1901 this->glLockOverlay(); 1902 this->actualOverlayRedraw(); 1903 this->glFlushBuffer(); 1904 this->glUnlockOverlay(); 1905} 1906 1907/*! 1908 This method renders the overlay scene. 1909*/ 1910void 1911So@Gui@RenderArea::actualOverlayRedraw(void) 1912{ 1913 assert(PRIVATE(this)->overlayManager != NULL); 1914 if (! this->isVisible()) return; 1915 PRIVATE(this)->overlayManager->render(PRIVATE(this)->clearOverlay, 1916 PRIVATE(this)->clearZBuffer); 1917} 1918 1919/*! 1920 This method is invoked to initialize the normal graphics. 1921*/ 1922void 1923So@Gui@RenderArea::initGraphic(void) 1924{ 1925 SoSceneManager * mgr = this->getSceneManager(); 1926 if (mgr) { 1927 mgr->reinitialize(); 1928 mgr->setRGBMode(this->isRGBMode()); 1929 1930 SoGLRenderAction * renderaction = mgr->getGLRenderAction(); 1931 renderaction->setCacheContext(SoAny::si()->getSharedCacheContextId(this)); 1932 SbBool isdirect = SoGuiGLWidgetP::isDirectRendering(this); 1933 renderaction->setRenderingIsRemote(!isdirect); 1934 } 1935 // FIXME: if not RGB mode, load colormap. pederb. 1936 1937 inherited::initGraphic(); 1938} 1939 1940/*! 1941 This method is invoked to initialize the overlay graphics. 1942*/ 1943void 1944So@Gui@RenderArea::initOverlayGraphic(void) 1945{ 1946 SoSceneManager * mgr = this->getOverlaySceneManager(); 1947 if (mgr) { 1948 mgr->reinitialize(); 1949 // FIXME: does overlays really _have_ to be in colorindex mode? 1950 // 20020916 mortene. 1951 mgr->setRGBMode(FALSE); 1952 1953 SoGLRenderAction * renderaction = mgr->getGLRenderAction(); 1954 SbBool isdirect = SoGuiGLWidgetP::isDirectRendering(this); 1955 renderaction->setRenderingIsRemote(!isdirect); 1956 // FIXME: shouldn't we also setCacheContext() on the renderaction? 1957 // 20020916 mortene. 1958 } 1959 // FIXME: if not RGB mode, load colormap. pederb. 1960 1961 // FIXME: shouldn't we do inherited::initOverlayGraphic() ? 20010831 mortene. 1962} 1963 1964// doc in super 1965void 1966So@Gui@RenderArea::sizeChanged(const SbVec2s & size) 1967{ 1968#if SO@GUI@_DEBUG && 0 1969 SoDebugError::postInfo("So@Gui@RenderArea::sizeChanged", 1970 "invoked, <%d, %d>", size[0], size[1]); 1971#endif // SO@GUI@_DEBUG 1972 1973 SbVec2s newsize(size); 1974 1975 if (size[0] == -1) 1976 return; 1977 1978 assert(PRIVATE(this)->normalManager != NULL); 1979 assert(PRIVATE(this)->overlayManager != NULL); 1980 1981 // Workaround for a bug in Qt/Mac 3.1.0 and 3.1.1 (which has been 1982 // confirmed fixed in 3.1.2): 1983 // 1984 // If the OpenGL context overlaps with the QSizeGrip widget 1985 // (generated by default), resizing does not work any more. The 1986 // workaround is to leave 15 pixels at the lower border of the 1987 // window blank... 1988 1989#if defined Q_OS_MAC && ((QT_VERSION == 0x030100) || (QT_VERSION == 0x030101)) 1990 1991 // Environment variable to override Qt/Mac 3.1.x workarounds. 1992 const char * forcenoresizeworkaround = 1993 SoAny::si()->getenv("FORCE_NO_QTMAC_31_RESIZE_WORKAROUND"); 1994 if (!forcenoresizeworkaround || (atoi(forcenoresizeworkaround) == 0)) { 1995 1996 if (this->getTypeId() == So@Gui@RenderArea::getClassTypeId()) { 1997 // SoQtRenderArea used as standalone component 1998 newsize -= SbVec2s(0, 15); 1999 2000 // spit out a warning that this is a Qt/Mac bug, not an SoQt problem 2001 const char * env = SoAny::si()->getenv("SOQT_NO_QTMAC_BUG_WARNINGS"); 2002 if (!env || !atoi(env)) { 2003 SoDebugError::postWarning("SoQtRenderArea::sizeChanged", 2004 "\nThis version of Qt/Mac contains a bug " 2005 "that makes it necessary to leave the\n" 2006 "lowermost 15 pixels of the viewer window " 2007 "blank. Set the environment variable\n" 2008 "FORCE_NO_QTMAC_31_RESIZE_WORKAROUND=1 to " 2009 "override this workaround. \n" 2010 "You can turn off warnings about Qt/Mac " 2011 "bugs permanently by setting \n" 2012 "SOQT_NO_QTMAC_BUG_WARNINGS=1.\n"); 2013 } 2014 } 2015 } 2016 2017#endif 2018 2019 this->setGLSize(newsize); 2020 const SbVec2s glsize = this->getGLSize(); 2021 2022 2023#if SO@GUI@_DEBUG && 0 2024 SoDebugError::postInfo("So@Gui@RenderArea::sizeChanged", 2025 "glsize==<%d, %d>", glsize[0], glsize[1]); 2026#endif // SO@GUI@_DEBUG 2027 2028 if (glsize[0] <= 0 || glsize[1] <= 0) 2029 return; 2030 2031 this->setViewportRegion(SbViewportRegion(glsize)); 2032 PRIVATE(this)->setDevicesWindowSize(glsize); 2033 2034 // FIXME: aren't both these calls unnecessary as we set the full 2035 // viewportregion a few lines above this one? 20020103 mortene. 2036 PRIVATE(this)->normalManager->setWindowSize(glsize); 2037 PRIVATE(this)->normalManager->setSize(glsize); 2038 2039 // FIXME: aren't both these calls unnecessary as we set the full 2040 // viewportregion a few lines above this one? 20020103 mortene. 2041 PRIVATE(this)->overlayManager->setWindowSize(glsize); 2042 PRIVATE(this)->overlayManager->setSize(glsize); 2043 2044 inherited::sizeChanged(glsize); 2045 2046 // this->scheduleRedraw(); // already done through setViewportRegion() 2047} 2048 2049// Documented in superclass. 2050void 2051So@Gui@RenderArea::widgetChanged(@WIDGET@ widget) 2052{ 2053 PRIVATE(this)->normalManager->reinitialize(); 2054 PRIVATE(this)->overlayManager->reinitialize(); 2055 // FIXME: colorindex mode not supported yet, so this has no 2056 // effect. 20001121 mortene. 2057#if 0 2058 PRIVATE(this)->normalManager->setRGBMode(this->isRGBMode()); 2059 PRIVATE(this)->overlayManager->setRGBMode(this->isRGBMode()); 2060#endif 2061 2062 // FIXME: should also walk through all registered devices and do a 2063 // disable() on the old widget and enable() on the new one. 2064 // 20001121 mortene. 2065} 2066 2067// Documented in superclass. 2068@WIDGET@ 2069So@Gui@RenderArea::buildWidget(@WIDGET@ parent) 2070{ 2071 @WIDGET@ widget = inherited::buildWidget(parent); 2072 2073 if (PRIVATE(this)->devicelist != NULL) { 2074 const int num = PRIVATE(this)->devicelist->getLength(); 2075 for (int i = 0; i < num; i++) { 2076 So@Gui@Device * device = (So@Gui@Device *) (*PRIVATE(this)->devicelist)[i]; 2077#ifdef __COIN_SOXT__ 2078 device->enable(this->getGLWidget(), 2079 (SoXtEventHandler *) &So@Gui@GLWidget::eventHandler, 2080 (void *) this); 2081#else 2082 device->enable(this->getGLWidget(), 2083 &So@Gui@GLWidgetP::eventHandler, (void *) this); 2084#endif 2085 } 2086 } 2087 2088 return widget; 2089} 2090 2091// Documented in superclass. 2092const char * 2093So@Gui@RenderArea::getDefaultWidgetName(void) const 2094{ 2095 static const char defaultWidgetName[] = "So@Gui@WidgetName"; 2096 return defaultWidgetName; 2097} 2098 2099// Documented in superclass. 2100const char * 2101So@Gui@RenderArea::getDefaultTitle(void) const 2102{ 2103 static const char defaultTitle[] = "@Gui@ RenderArea"; 2104 return defaultTitle; 2105} 2106 2107// Documented in superclass. 2108const char * 2109So@Gui@RenderArea::getDefaultIconTitle(void) const 2110{ 2111 static const char defaultIconTitle[] = "@Gui@ RenderArea"; 2112 return defaultIconTitle; 2113} 2114 2115// ************************************************************************* 2116 2117/*! 2118 Toolkit-native events are attempted converted to Coin-generic events 2119 in the So@Gui@RenderArea::processEvent() method. If this succeeds, 2120 they are forwarded to this method. 2121 2122 This is a virtual method, and is overridden in it's subclasses to 2123 catch events of particular interest to the viewer classes, for 2124 instance. 2125 2126 Return \c TRUE iff the event was processed. If not it should be 2127 passed on further up in the inheritance hierarchy by the caller. 2128 This last point is extremely important to take note of if you are 2129 expanding the toolkit with your own viewer class. 2130 2131 This method is not part of the original SGI InventorXt API. Note 2132 that you can still override the toolkit-native processEvent() method 2133 instead of this "generic" method. 2134*/ 2135SbBool 2136So@Gui@RenderArea::processSoEvent(const SoEvent * const event) 2137{ 2138 if (PRIVATE(this)->overlayManager->processEvent(event)) { return TRUE; } 2139 if (PRIVATE(this)->normalManager->processEvent(event)) { return TRUE; } 2140 return FALSE; 2141} 2142 2143// ************************************************************************* 2144 2145/*! 2146 Overrides So@Gui@GLWidget::processEvent() to attempt to convert 2147 toolkit-native events to Coin-generic events. If this succeeds, the 2148 generic SoEvent is forwarded to So@Gui@RenderArea::processSoEvent(). 2149 */ 2150void 2151So@Gui@RenderArea::processEvent(@EVENT@ event) 2152{ 2153 // FIXME: This method is not reentrant, but certain GUI toolkits may 2154 // run the event-loop recursively with events injected while processing 2155 // other events. We must detect when this happens, and queue up the 2156 // event for delayed processing after the primary event is done processing. 2157 // This means event instances can not be static and rewritten in the 2158 // device handlers like they are currently... 20051013 larsa 2159 2160 if (PRIVATE(this)->invokeAppCB(event)) { return; } 2161 2162 const SoEvent * soevent = PRIVATE(this)->getSoEvent(event); 2163 2164 if (soevent != NULL) { 2165#if SO@GUI@_DEBUG || defined(DEBUGGING_EGGS) 2166 // Undocumented feature: there are several "magic" sequences of 2167 // keys when tapped into the rendering canvas which'll pop up a 2168 // dialog box with information about that particular feature. 2169 // 2170 // See code comments behind "case" statements below for which 2171 // sequences are available so far. 2172 2173 if (soevent->isOfType(SoKeyboardEvent::getClassTypeId())) { 2174 SoKeyboardEvent * ke = (SoKeyboardEvent *)soevent; 2175 if (ke->getState() == SoButtonEvent::UP) { 2176 char c = ke->getPrintableCharacter(); 2177 switch (PRIVATE(this)->checkMagicSequences(c)) { 2178 case So@Gui@RenderAreaP::NONE: 2179 break; 2180 case So@Gui@RenderAreaP::OPENGL: // "glinfo" 2181 this->glLockNormal(); 2182 PRIVATE(this)->showOpenGLDriverInformation(); 2183 this->glUnlockNormal(); 2184 break; 2185 case So@Gui@RenderAreaP::INVENTOR: // "ivinfo" 2186 PRIVATE(this)->showInventorInformation(); 2187 break; 2188 case So@Gui@RenderAreaP::TOOLKIT: // "soinfo" 2189 PRIVATE(this)->showToolkitInformation(); 2190 break; 2191 case So@Gui@RenderAreaP::DUMPSCENEGRAPH: // "dumpiv" 2192 PRIVATE(this)->dumpScenegraph(); 2193 break; 2194 case So@Gui@RenderAreaP::DUMPCAMERAS: // "cameras" 2195 PRIVATE(this)->dumpCameras(); 2196 break; 2197 case So@Gui@RenderAreaP::OFFSCREENGRAB: // "osgrab" 2198 PRIVATE(this)->offScreenGrab(); 2199 break; 2200 default: 2201 assert(FALSE && "unknown debug key sequence"); 2202 break; 2203 } 2204 } 2205 } 2206#endif // SO@GUI@_DEBUG 2207 2208 SbBool processed = this->processSoEvent(soevent); 2209 if (processed) return; 2210 } 2211 2212 inherited::processEvent(event); 2213} 2214 2215// ************************************************************************* 2216 2217// doc from parent 2218SbBool 2219So@Gui@RenderArea::glScheduleRedraw(void) 2220{ 2221 this->scheduleRedraw(); 2222 if (this->hasOverlayGLArea() && this->getOverlaySceneGraph()) { 2223 this->scheduleOverlayRedraw(); 2224 } 2225 return TRUE; 2226} 2227 2228// ************************************************************************* 2229 2230/*! 2231 This method posts and processes an SoEvent object to the 2232 So@Gui@RenderArea-based component and returns the result value from the 2233 event handler. This is a synchronous operation. 2234*/ 2235SbBool 2236So@Gui@RenderArea::sendSoEvent(const SoEvent * event) 2237{ 2238 return this->processSoEvent(event); 2239} 2240 2241// ************************************************************************* 2242 2243#undef PRIVATE 2244#undef PUBLIC 2245 2246