1
/**************************************************************************\
3
* This file is part of the Coin 3D visualization library.
4
* Copyright (C) 1998-2005 by Systems in Motion. All rights reserved.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* ("GPL") version 2 as published by the Free Software Foundation.
9
* See the file LICENSE.GPL at the root directory of this source
10
* distribution for additional information about the GNU GPL.
12
* For using Coin with software that can not be combined with the GNU
13
* GPL, and for taking advantage of the additional benefits of our
14
* support services, please contact Systems in Motion about acquiring
15
* a Coin Professional Edition License.
17
* See <URL:http://www.coin3d.org/> for more information.
19
* Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY.
20
* <URL:http://www.sim.no/>.
22
\**************************************************************************/
24
// src/Inventor/Qt/SoQtRenderArea.cpp. Generated from SoGuiRenderArea.cpp.in by configure.
26
/**************************************************************************\
30
* It is fruitless to modify the contents of the SoQtRenderArea.cpp file
31
* because it is autogenerated by configure from the SoGuiRenderArea.cpp.in
32
* file which you will find in the src/Inventor/Qt/common/ directory.
33
* Do your modifications to that file instead.
35
\**************************************************************************/
37
// *************************************************************************
40
\class SoQtRenderArea Inventor/Qt/SoQtRenderArea.h
41
\brief The SoQtRenderArea class adds scenegraph handling and event management.
42
\ingroup components viewers
44
The SoQtRenderArea class is a component that adds scenegraph
45
management and input device event handling to the SoQtGLWidget
48
The class has many convenient methods for controlling aspects of the
49
rendering, like for instance transparency, aliasing and for
50
scheduling of redraws.
52
Native toolkit events are caught by SoQtRenderArea components,
53
translated to Coin SoEvent instances and passed on to the
54
scenegraph, in case the user is doing interactive operations on for
55
instance Coin geometry draggers.
58
SoQtRenderArea is the first non-abstract component in it's
59
inheritance hierarchy that you can use directly from client
60
application code to set up a scenegraph viewer canvas.
62
For an SoQtRenderArea component to properly display your
63
scenegraph, it must contain an SoCamera-derived node and at least
64
one SoLight-derived lightsource node.
66
Here's a complete, stand-alone example on how to set up an
67
SoQtRenderArea with a scenegraph:
70
#include <Inventor/Qt/SoQt.h>
71
#include <Inventor/Qt/SoQtRenderArea.h>
73
#include <Inventor/nodes/SoCube.h>
74
#include <Inventor/nodes/SoRotor.h>
75
#include <Inventor/nodes/SoArray.h>
76
#include <Inventor/nodes/SoDirectionalLight.h>
77
#include <Inventor/nodes/SoPerspectiveCamera.h>
78
#include <Inventor/nodes/SoSeparator.h>
80
// Set up a simple scenegraph, just for demonstration purposes.
84
SoSeparator * root = new SoSeparator;
86
SoGroup * group = new SoGroup;
88
SoRotor * rotor = new SoRotor;
89
rotor->rotation = SbRotation(SbVec3f(0.2, 0.5, 0.9), M_PI/4.0);
90
group->addChild(rotor);
92
SoCube * cube = new SoCube;
93
group->addChild(cube);
95
SoArray * array = new SoArray;
96
array->origin = SoArray::CENTER;
97
array->addChild(group);
98
array->numElements1 = 2;
99
array->numElements2 = 2;
100
array->separation1 = SbVec3f(4, 0, 0);
101
array->separation2 = SbVec3f(0, 4, 0);
103
root->addChild(array);
108
main(int argc, char ** argv)
110
QWidget * window = SoQt::init(argv[0]);
112
SoSeparator * root = new SoSeparator;
115
SoPerspectiveCamera * camera;
116
root->addChild(camera = new SoPerspectiveCamera);
118
root->addChild(new SoDirectionalLight);
120
SoSeparator * userroot = get_scene_graph();
121
root->addChild(userroot);
123
SoQtRenderArea * renderarea = new SoQtRenderArea(window);
124
camera->viewAll(userroot, renderarea->getViewportRegion());
125
renderarea->setSceneGraph(root);
126
renderarea->setBackgroundColor(SbColor(0.0f, 0.2f, 0.3f));
128
renderarea->setTitle(argv[1]);
129
renderarea->setIconTitle(argv[1]);
144
// *************************************************************************
146
#include <Inventor/Qt/SoQtRenderArea.h>
148
#include <string.h> // strchr()
152
#endif // HAVE_CONFIG_H
154
#if SOQT_DEBUG // For the "soinfo" debugging backdoor.
156
#include <qapplication.h>
159
#include <Inventor/Qt/common/gl.h> // glDrawBuffer()
161
#include <Inventor/SoSceneManager.h>
162
#include <Inventor/actions/SoSearchAction.h>
163
#include <Inventor/actions/SoWriteAction.h>
164
#include <Inventor/errors/SoDebugError.h>
165
#include <Inventor/events/SoKeyboardEvent.h>
166
#include <Inventor/misc/SoBasic.h>
167
#include <Inventor/nodekits/SoBaseKit.h>
168
#include <Inventor/nodes/SoCamera.h>
169
#include <Inventor/nodes/SoSelection.h>
170
#include <Inventor/SoOffscreenRenderer.h>
172
#include <soqtdefs.h>
173
#include <Inventor/Qt/SoQtBasic.h>
174
#include <Inventor/Qt/SoQt.h>
175
#include <Inventor/Qt/devices/SoQtKeyboard.h>
176
#include <Inventor/Qt/devices/SoQtMouse.h>
177
#include <Inventor/Qt/devices/SoQtSpaceball.h>
178
#ifdef HAVE_JOYSTICK_LINUX
179
#include <Inventor/Qt/devices/SoQtLinuxJoystick.h>
180
#endif // HAVE_JOYSTICK_LINUX
182
#include <Inventor/Qt/SoQtGLWidgetP.h>
183
#include <Inventor/Qt/SoAny.h>
185
#define RENDERAREA_DEBUG_REDRAWS 0
187
#define PRIVATE(obj) ((obj)->pimpl)
188
#define PUBLIC(obj) ((obj)->pub)
190
// *************************************************************************
192
SOQT_OBJECT_SOURCE(SoQtRenderArea);
194
// *************************************************************************
196
#ifndef DOXYGEN_SKIP_THIS
198
class SoQtRenderAreaP {
201
SoQtRenderAreaP(class SoQtRenderArea * pub);
202
~SoQtRenderAreaP(void);
208
SoSceneManager * normalManager;
209
SoSceneManager * overlayManager;
211
SbColor * normalColormap;
212
int normalColormapSize;
213
int normalColormapStart;
214
SbColor * overlayColormap;
215
int overlayColormapSize;
216
int overlayColormapStart;
218
SbPList * devicelist;
221
SoQtKeyboard * keyboard;
227
void replaceSoSelectionMonitor(SoSelection * newsel, SoSelection * oldsel) const;
228
SoSelection * normalselection;
229
SoSelection * overlayselection;
231
static const int GL_DEFAULT_MODE;
233
void constructor(SbBool mouseInput, SbBool keyboardInput, SbBool build);
234
static void renderCB(void * user, SoSceneManager * manager);
235
static void selection_redraw_cb(void * data, SoSelection * sel);
236
void setDevicesWindowSize(const SbVec2s size);
238
// OpenGL info-window hack.
239
enum { NONE, OPENGL, INVENTOR, TOOLKIT, DUMPSCENEGRAPH, DUMPCAMERAS, OFFSCREENGRAB };
240
int checkMagicSequences(const char c);
241
void showOpenGLDriverInformation(void);
242
void showInventorInformation(void);
243
void showToolkitInformation(void);
244
void dumpScenegraph(void);
245
void dumpCameras(void);
246
void offScreenGrab(void);
248
SbBool invokeAppCB(QEvent * event);
249
const SoEvent * getSoEvent(QEvent * event);
251
SoQtRenderAreaEventCB * appeventhandler;
252
void * appeventhandlerdata;
255
SoQtRenderArea * pub; // public interface class
256
SbString currentinput; // For the OpenGL info-window hack.
259
const int SoQtRenderAreaP::GL_DEFAULT_MODE = (SO_GL_RGB |
263
#if SOQT_DEBUG && defined(__COIN__)
264
// Disabled when compiling against SGI / TGS Inventor, as we're using
265
// our Coin-specific extension SbString::sprintf() a lot.
266
#define DEBUGGING_EGGS 1
267
#endif // SOQT_DEBUG && __COIN__
269
// Note: assumes a valid current OpenGL context.
271
SoQtRenderAreaP::showOpenGLDriverInformation(void)
274
const GLubyte * vendor = glGetString(GL_VENDOR);
275
const GLubyte * renderer = glGetString(GL_RENDERER);
276
const GLubyte * version = glGetString(GL_VERSION);
277
const GLubyte * extensions = glGetString(GL_EXTENSIONS);
279
SbString info = "GL_VENDOR: \""; info += (const char *)vendor; info += "\"\n";
280
info += "GL_RENDERER: \""; info += (const char *)renderer; info += "\"\n";
281
info += "GL_VERSION: \""; info += (const char *)version; info += "\"\n";
282
info += "GL_EXTENSIONS: \"\n ";
284
SbString exts = (const char *)extensions;
287
// (the extra parentheses in the while-expression kills a gcc warning)
288
while ((p = strchr(exts.getString(), ' '))) {
289
const char * start = exts.getString();
290
info += exts.getSubString(0, p - start);
291
exts.deleteSubString(0, p - start);
293
if (count == 4) { // number of extensions listed on each line
298
if (exts.getLength() > 0) { info += "\n "; info += exts; }
301
// FIXME: should also show available GLX / WGL / AGL
302
// extensions. 20020802 mortene.
304
// Misc implementation info
308
PUBLIC(this)->getPointSizeLimits(range, granularity);
311
s.sprintf("glPointSize(): range=[%f, %f], granularity=%f\n",
312
range[0], range[1], granularity);
316
PUBLIC(this)->getLineWidthLimits(range, granularity);
318
s.sprintf("glLineWidth(): range=[%f, %f], granularity=%f\n",
319
range[0], range[1], granularity);
323
glGetIntegerv(GL_DEPTH_BITS, depthbits);
324
s.sprintf("GL_DEPTH_BITS==%d\n", depthbits[0]);
328
glGetIntegerv(GL_RED_BITS, &colbits[0]);
329
glGetIntegerv(GL_GREEN_BITS, &colbits[1]);
330
glGetIntegerv(GL_BLUE_BITS, &colbits[2]);
331
glGetIntegerv(GL_ALPHA_BITS, &colbits[3]);
332
s.sprintf("GL_[RED|GREEN|BLUE|ALPHA]_BITS==[%d, %d, %d, %d]\n",
333
colbits[0], colbits[1], colbits[2], colbits[3]);
337
glGetIntegerv(GL_ACCUM_RED_BITS, &accumbits[0]);
338
glGetIntegerv(GL_ACCUM_GREEN_BITS, &accumbits[1]);
339
glGetIntegerv(GL_ACCUM_BLUE_BITS, &accumbits[2]);
340
glGetIntegerv(GL_ACCUM_ALPHA_BITS, &accumbits[3]);
341
s.sprintf("GL_ACCUM_[RED|GREEN|BLUE|ALPHA]_BITS==[%d, %d, %d, %d]\n",
342
accumbits[0], accumbits[1], accumbits[2], accumbits[3]);
346
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxdims);
347
s.sprintf("GL_MAX_VIEWPORT_DIMS==<%d, %d>\n", maxdims[0], maxdims[1]);
351
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texdim);
352
s.sprintf("GL_MAX_TEXTURE_SIZE==%d\n", texdim);
356
glGetIntegerv(GL_MAX_LIGHTS, &maxlights);
357
s.sprintf("GL_MAX_LIGHTS==%d\n", maxlights);
361
glGetIntegerv(GL_MAX_CLIP_PLANES, &maxplanes);
362
s.sprintf("GL_MAX_CLIP_PLANES==%d\n", maxplanes);
365
// FIXME: other implementation specifics to print are
367
// * maximum stack depths (attribute, modelview matrix, name,
368
// projection matrix, texture matrix)
370
// * max display list nesting
372
// * max 3D texture size (needs specific extension?)
379
"Rendering is %sdirect.\n",
380
SoGuiGLWidgetP::isDirectRendering(PUBLIC(this)) ? "" : "in");
383
SoQt::createSimpleErrorDialog(NULL, "OpenGL driver information",
385
#endif // DEBUGGING_EGGS
389
SoQtRenderAreaP::showInventorInformation(void)
393
info.sprintf("%s\n", SoDB::getVersion());
395
// Display calculated maximum resolution of SbTime::getTimeOfDay().
397
const double DURATION = 0.2; // in seconds
398
SbTime current = SbTime::getTimeOfDay();
399
SbTime end(current + DURATION);
400
SbTime last = current;
401
unsigned int ticks = 0;
403
current = SbTime::getTimeOfDay();
404
if (current.getValue() != last.getValue()) { ticks++; last = current; }
405
} while (current < end);
407
s.sprintf("\nSbTime::getTimeOfDay() resolution: ~ %d Hz\n",
408
(int)(((double)ticks) / DURATION));
412
// FIXME: dump list of available node classes? 20010927 mortene.
413
SoQt::createSimpleErrorDialog(NULL, "Inventor implementation info",
416
#endif // DEBUGGING_EGGS
420
SoQtRenderAreaP::showToolkitInformation(void)
423
SbString info = "SoQt version "; info += SOQT_VERSION; info += "\n";
425
info += "Built as MSWindows DLL.\n";
426
#endif // !SOQT_MAKE_DLL
428
// FIXME: include information about the underlying toolkit library,
429
// if possible, like we do for Qt below (ie Gtk version, Motif
430
// implementation, MSWindows version, ...). 20010927 mortene.
433
// Qt implementation info.
436
s.sprintf("\nQt version: %s\n", qVersion());
439
#endif // SOQT_INTERNAL
441
// FIXME: information about DLL path(s) (both for the SoQt and
442
// Coin/Inventor library) would be _extremely_ useful for debugging
443
// "remote" applications, as application programmers (including
444
// ourselves) tend to spread those files around misc diskdrive
445
// directories -- especially on MSWindows platforms. Mismatches for
446
// run-time binding and link-time binding then causes bugs which are
447
// impossible to make sense of.
449
// I don't know if any platforms have enough introspection
450
// functionality to enable us to do this, though. Should
451
// investigate. (update: GetModuleHandle() looks like the place to
452
// start looking in the Win32 API.)
456
// OpenGL canvas settings.
459
s.sprintf("\nCurrent OpenGL canvas:\n"
461
" drawing to %sbuffer\n"
464
" with%s overlay planes\n",
465
PUBLIC(this)->isDoubleBuffer() ? "double" : "single",
466
PUBLIC(this)->isDrawToFrontBufferEnable() ? "front" : "back",
467
PUBLIC(this)->isStereoBuffer() ? "stereo" : "mono",
468
PUBLIC(this)->isQuadBufferStereo() ? " (OpenGL quadbuffer)" : "",
469
PUBLIC(this)->isRGBMode() ? "RGB" : "colorindex",
470
PUBLIC(this)->isOverlayRender() ? "" : "out");
472
// FIXME: information about the native OpenGL widget format?
478
// Underlying Inventor implementation.
481
s.sprintf("\nInventor implementation: %s\n", SoDB::getVersion());
485
SoQt::createSimpleErrorDialog(NULL, "SoQt implementation info",
487
#endif // DEBUGGING_EGGS
491
SoQtRenderAreaP::dumpScenegraph(void)
493
#ifdef DEBUGGING_EGGS
495
SbString filename = SbTime::getTimeOfDay().format();
496
filename += "-dump.iv";
497
SbBool ok = out.openFile(filename.getString());
499
SoDebugError::post("SoQtRenderAreaP::dumpScenegraph",
500
"couldn't open file '%s'", filename.getString());
503
SoWriteAction wa(&out);
504
wa.apply(this->normalManager->getSceneGraph());
505
SoDebugError::postInfo("SoQtRenderAreaP::dumpScenegraph",
506
"dumped scenegraph to '%s'", filename.getString());
507
#endif // DEBUGGING_EGGS
511
SoQtRenderAreaP::dumpCameras(void)
513
#ifdef DEBUGGING_EGGS
514
const SbBool kitsearch = SoBaseKit::isSearchingChildren();
515
SoBaseKit::setSearchingChildren(TRUE);
517
SoSearchAction search;
518
search.setType(SoCamera::getClassTypeId());
519
search.setInterest(SoSearchAction::ALL);
520
search.setSearchingAll(TRUE);
521
search.apply(this->normalManager->getSceneGraph());
523
SoBaseKit::setSearchingChildren(kitsearch);
525
const SoPathList & pl = search.getPaths();
526
const unsigned int numcams = pl.getLength();
527
SoDebugError::postInfo("SoQtRenderAreaP::dumpCameras",
528
"Number of cameras in scene graph: %d",
531
for (unsigned int i = 0; i < numcams; i++) {
532
const SoPath * p = pl[i];
533
SoNode * n = p->getTail();
534
assert(n->isOfType(SoCamera::getClassTypeId()));
535
SoCamera * cam = (SoCamera *)n;
537
const SbVec3f pos = cam->position.getValue();
538
const SbRotation rot = cam->orientation.getValue();
541
rot.getValue(axis, angle);
543
SoDebugError::postInfo("SoQtRenderAreaP::dumpCameras",
544
"type==%s, name=='%s', position==<%f, %f, %f>, "
545
"orientation-rotation==<%f, %f, %f>--%f",
546
cam->getTypeId().getName().getString(),
547
cam->getName().getString(),
548
pos[0], pos[1], pos[2],
549
axis[0], axis[1], axis[2], angle);
551
#endif // DEBUGGING_EGGS
555
Behaviour controlled by environment variables
556
COIN_SOGRAB_GEOMETRY (maximum geometry - on-screen aspect is preserved)
557
COIN_SOGRAB_FILENAME (filename template - can use %d to insert counter)
560
export COIN_SOGRAB_GEOMETRY=1024x768
561
export COIN_SOGRAB_FILENAME=c:\\grab%03d.png
566
SoQtRenderAreaP::offScreenGrab(void)
568
#ifdef DEBUGGING_EGGS
569
static int maxwidth = -1;
570
static int maxheight = -1;
571
static int counter = 0;
572
static const char fallback_ext[] = ".rgb";
573
static const char fallback_name[] = "coingrab%03d.rgb";
578
- schedule a regular render-pass and hook into the render
579
pipe-line to check all the interesting GL context features that
580
might need to be enabled for the offscreen renderer context.
581
Then set up the offscreen renderer context to match those
582
features, so the rendering becomes the same.
583
- create a clone of the on-screen renderaction to get the same
584
kind of custom rendering.
585
- check if we might be able to hook up the on-screen pre-render
586
callback to the offscreen renderer as well, if any point.
587
- disable accidentally enabled seek mode again (from typing 'osgrab').
593
if ( maxwidth <= 0 ) {
595
SoAny::si()->getenv("COIN_SOGRAB_GEOMETRY");
597
sscanf(env, "%dx%d", &maxwidth, &maxheight);
599
if ( (maxwidth <= 0) || !env ) {
600
SbVec2s vp = PUBLIC(this)->getViewportRegion().getWindowSize();
606
if ( maxwidth <= 0 || maxheight <= 0 ) {
607
SoDebugError::post("SoQtRenderAreaP::offScreenGrab",
608
"invalid geometry: %dx%d", maxwidth, maxheight);
611
SbVec2s vp = PUBLIC(this)->getViewportRegion().getWindowSize();
613
const char * filenametpl =
614
SoAny::si()->getenv("COIN_SOGRAB_FILENAME");
615
if ( !filenametpl ) filenametpl = fallback_name;
618
filename.sprintf(filenametpl, counter);
619
const char * ext = strrchr(filename.getString(), '.');
620
if ( !ext ) ext = fallback_ext;
623
SbVec2s osvp(maxwidth, maxheight);
624
if ( vp[0] > maxwidth || vp[1] > maxheight ||
625
(vp[0] < maxwidth && vp[1] < maxheight) ) {
626
float onscaspect = float(vp[0]) / float(vp[1]);
627
float offscaspect = float(maxwidth) / float(maxheight);
630
osvp[0] = short(maxheight * onscaspect);
631
if ( osvp[0] > maxwidth ) {
633
osvp[1] = short(maxwidth * (1.0f / onscaspect));
637
SoOffscreenRenderer os(osvp);
638
if ( !os.render(PUBLIC(this)->getSceneManager()->getSceneGraph()) ) {
642
if ( !os.writeToFile(filename, ext) && (strcmp(ext, "rgb") != 0) ) {
644
fname2.sprintf("%s.rgb", filename.getString());
645
os.writeToRGB(fname2.getString());
648
SoDebugError::postInfo("SoQtRenderAreaP::offScreenGrab",
649
"wrote image #%d, %dx%d",
650
counter, osvp[0], osvp[1]);
651
#endif // DEBUGGING_EGGS
655
SoQtRenderAreaP::checkMagicSequences(const char c)
658
this->currentinput += c;
660
if (0) { // handy for debugging keyboard handling
661
SoDebugError::postInfo("SoQtRenderAreaP::checkMagicSequences",
662
"'%s'", this->currentinput.getString());
665
const int cl = this->currentinput.getLength();
667
static const char * keyseq[] = {
668
"glinfo", "ivinfo", "soinfo", "dumpiv", "cameras", "osgrab"
670
static const int id[] = {
671
SoQtRenderAreaP::OPENGL,
672
SoQtRenderAreaP::INVENTOR,
673
SoQtRenderAreaP::TOOLKIT,
674
SoQtRenderAreaP::DUMPSCENEGRAPH,
675
SoQtRenderAreaP::DUMPCAMERAS,
676
SoQtRenderAreaP::OFFSCREENGRAB
679
for (unsigned int i = 0; i < (sizeof(keyseq) / sizeof(keyseq[0])); i++) {
680
const int ml = strlen(keyseq[i]);
681
if (cl >= ml && this->currentinput.getSubString(cl - ml) == keyseq[i]) {
686
// Limit memory usage.
687
if (cl > 1024) { this->currentinput = ""; }
688
#endif // DEBUGGING_EGGS
690
return SoQtRenderAreaP::NONE;
693
// This method sets the window size data in all the connected device
696
SoQtRenderAreaP::setDevicesWindowSize(const SbVec2s size)
698
if (!this->devicelist) return;
699
const int num = this->devicelist->getLength();
700
for (int i = 0; i < num; i++)
701
((SoQtDevice *)(*this->devicelist)[i])->setWindowSize(size);
704
// *************************************************************************
707
SoQtRenderAreaP::renderCB(void * closure, SoSceneManager * manager)
709
assert(closure && manager);
710
SoQtRenderArea * thisptr = (SoQtRenderArea *) closure;
711
if (manager == PRIVATE(thisptr)->normalManager) {
713
} else if (manager == PRIVATE(thisptr)->overlayManager) {
714
thisptr->renderOverlay();
717
SoDebugError::post("SoQtRenderAreaP::renderCB",
718
"invoked for unknown SoSceneManager (%p)", manager);
720
manager->setRenderCallback(NULL, NULL);
724
if (!thisptr->isAutoRedraw())
725
manager->setRenderCallback(NULL, NULL);
728
// Callback for automatic redraw on SoSelection changes.
730
SoQtRenderAreaP::selection_redraw_cb(void * closure, SoSelection * sel)
732
SoQtRenderArea * ra = (SoQtRenderArea *) closure;
733
if (sel == PRIVATE(ra)->normalselection)
734
ra->scheduleRedraw();
735
else if (sel == PRIVATE(ra)->overlayselection)
736
ra->scheduleOverlayRedraw();
738
assert(0 && "callback on unknown SoSelection node");
741
// Private class constructor.
742
SoQtRenderAreaP::SoQtRenderAreaP(SoQtRenderArea * api)
746
this->normalManager = new SoSceneManager;
747
this->overlayManager = new SoSceneManager;
749
this->normalColormap = NULL;
750
this->normalColormapSize = 0;
751
this->overlayColormap = NULL;
752
this->overlayColormapSize = 0;
755
this->clearZBuffer = TRUE;
756
this->clearOverlay = TRUE;
757
this->autoRedraw = TRUE;
759
this->normalselection = NULL;
760
this->overlayselection = NULL;
762
this->devices.mouse = NULL;
763
this->devices.keyboard = NULL;
766
// Private class destructor.
767
SoQtRenderAreaP::~SoQtRenderAreaP()
769
delete this->normalManager;
770
delete this->overlayManager;
771
delete [] this->normalColormap;
772
delete [] this->overlayColormap;
775
// Common code for all constructors.
777
SoQtRenderAreaP::constructor(SbBool mouseInput,
778
SbBool keyboardInput,
781
this->normalManager->setRenderCallback(SoQtRenderAreaP::renderCB, PUBLIC(this));
782
this->normalManager->activate();
783
this->overlayManager->setRenderCallback(SoQtRenderAreaP::renderCB, PUBLIC(this));
784
this->overlayManager->activate();
785
// FIXME: what is this magic number doing here - shouldn't we use
786
// SoGLCacheContextElement::getUniqueCacheContext() for Coin, and
787
// magic numbers just for SGI / TGS Inventor?
789
// On a side note: won't this code fail if we construct several
790
// SoQtRenderArea instances with overlays? They will all use
791
// cachecontext==1 for their SoGLRenderAction instances -- is that
795
this->overlayManager->getGLRenderAction()->setCacheContext(1);
797
this->appeventhandler = NULL;
798
this->appeventhandlerdata = NULL;
800
this->devicelist = new SbPList;
803
this->devices.mouse = new SoQtMouse;
804
PUBLIC(this)->registerDevice(this->devices.mouse);
808
this->devices.keyboard = new SoQtKeyboard;
809
PUBLIC(this)->registerDevice(this->devices.keyboard);
813
PUBLIC(this)->setClassName("SoQtRenderArea");
814
QWidget * glarea = PUBLIC(this)->buildWidget(PUBLIC(this)->getParentWidget());
815
PUBLIC(this)->setBaseWidget(glarea);
816
PUBLIC(this)->setSize(SbVec2s(400, 400));
819
// This method invokes the application event handler, if one is set.
821
SoQtRenderAreaP::invokeAppCB(QEvent * event)
823
if (this->appeventhandler != NULL)
824
return this->appeventhandler(this->appeventhandlerdata, event);
828
// This method returns an SoEvent * corresponding to the given \a
829
// event, or \c NULL if there are none.
831
SoQtRenderAreaP::getSoEvent(QEvent * event)
833
if (!this->devicelist)
834
return (SoEvent *) NULL;
836
const SoEvent * soevent = NULL;
837
const int num = this->devicelist->getLength();
838
for (int i = 0; (i < num) && (soevent == NULL); i++)
839
soevent = ((SoQtDevice *)(*this->devicelist)[i])->translateEvent(event);
844
#endif // DOXYGEN_SKIP_THIS
846
// *************************************************************************
851
SoQtRenderArea::SoQtRenderArea(QWidget * parent,
855
SbBool keyboardInput)
856
: inherited(parent, name, embed, SoQtRenderAreaP::GL_DEFAULT_MODE, FALSE)
858
PRIVATE(this) = new SoQtRenderAreaP(this);
859
PRIVATE(this)->constructor(mouseInput, keyboardInput, TRUE);
863
Protected constructor used by derived classes.
865
SoQtRenderArea::SoQtRenderArea(QWidget * parent,
869
SbBool keyboardInput,
871
: inherited(parent, name, embed, SoQtRenderAreaP::GL_DEFAULT_MODE, FALSE)
873
PRIVATE(this) = new SoQtRenderAreaP(this);
874
PRIVATE(this)->constructor(mouseInput, keyboardInput, build);
880
SoQtRenderArea::~SoQtRenderArea()
882
// Clean out any callbacks we may have registered with SoSelection
884
this->redrawOverlayOnSelectionChange(NULL);
885
this->redrawOnSelectionChange(NULL);
887
for (int i = PRIVATE(this)->devicelist->getLength() - 1; i >= 0; i--) {
888
SoQtDevice * device = (SoQtDevice *) ((*PRIVATE(this)->devicelist)[i]);
889
this->unregisterDevice(device);
892
delete PRIVATE(this)->devicelist;
893
delete PRIVATE(this);
896
// *************************************************************************
899
This method adds \a device to the list of devices handling events
903
SoQtRenderArea::registerDevice(SoQtDevice * device)
905
int idx = PRIVATE(this)->devicelist->find(device);
908
SoDebugError::postWarning("SoQtRenderArea::registerDevice",
909
"device already registered");
914
PRIVATE(this)->devicelist->append(device);
915
QWidget * w = this->getGLWidget();
918
device->enable(w, (SoXtEventHandler *) &SoQtGLWidget::eventHandler, (void *)this);
920
device->enable(w, &SoQtGLWidgetP::eventHandler, (void *)this);
922
device->setWindowSize(this->getGLSize());
927
This method removes \a device from the list of devices handling
928
events for this component.
931
SoQtRenderArea::unregisterDevice(SoQtDevice * device)
933
assert(PRIVATE(this)->devicelist != NULL);
934
const int idx = PRIVATE(this)->devicelist->find(device);
937
SoDebugError::post("SoQtRenderArea::unregisterDevice",
938
"tried to remove nonexisting device");
943
PRIVATE(this)->devicelist->remove(idx);
944
QWidget * w = this->getGLWidget();
945
if (w != NULL) { device->disable(w, NULL, NULL); }
948
// *************************************************************************
950
// Documented in superclass.
952
SoQtRenderArea::afterRealizeHook(void)
954
inherited::afterRealizeHook();
956
#ifdef HAVE_JOYSTICK_LINUX
957
if (SoQtLinuxJoystick::exists())
958
this->registerDevice(new SoQtLinuxJoystick);
959
#endif // HAVE_JOYSTICK_LINUX
961
if (SoQtSpaceball::exists())
962
this->registerDevice(new SoQtSpaceball);
966
This method sets the scene graph to be rendered in the normal bitmap
969
\sa getSceneGraph(), setOverlaySceneGraph()
972
SoQtRenderArea::setSceneGraph(SoNode * scene)
974
PRIVATE(this)->normalManager->setSceneGraph(scene);
978
This method returns a reference to the scene graph root node as set
981
\sa SoQtRenderArea::getSceneManager()
984
SoQtRenderArea::getSceneGraph(void)
986
return PRIVATE(this)->normalManager->getSceneGraph();
990
This method sets the scene graph to render for the overlay bitmap
993
It will automatically take care of setting up overplay planes in the
994
OpenGL canvas if the OpenGL hardware and driver supports it.
996
Important note: not all graphics hardware and / or drivers for
997
graphics hardware support overlay planes, so application programmers
998
are adviced to find some other way of accomplishing what they want
999
to do before resorting to using overlay planes. Using overlay
1000
planes will in practice severely limit the portability of
1001
applications which depend on them being available.
1003
\sa setSceneGraph(), getOverlaySceneGraph()
1006
SoQtRenderArea::setOverlaySceneGraph(SoNode * scene)
1008
SoNode * oldroot = this->getOverlaySceneGraph();
1009
PRIVATE(this)->overlayManager->setSceneGraph(scene);
1011
if (!oldroot && scene) { this->setOverlayRender(TRUE); }
1012
else if (oldroot && !scene) { this->setOverlayRender(FALSE); }
1016
This method returns the scene graph for the overlay scene.
1019
SoQtRenderArea::getOverlaySceneGraph(void)
1021
return PRIVATE(this)->overlayManager->getSceneGraph();
1024
// *************************************************************************
1027
This method sets the background color of the scene.
1030
SoQtRenderArea::setBackgroundColor(const SbColor & color)
1032
assert(PRIVATE(this)->normalManager != NULL);
1033
PRIVATE(this)->normalManager->setBackgroundColor(color);
1034
this->scheduleRedraw();
1038
This method returns the background color for the scene.
1041
SoQtRenderArea::getBackgroundColor(void) const
1043
assert(PRIVATE(this)->normalManager != NULL);
1044
return PRIVATE(this)->normalManager->getBackgroundColor();
1047
// *************************************************************************
1050
This method sets the index of the background color for the scene.
1053
SoQtRenderArea::setBackgroundIndex(int idx)
1055
assert(PRIVATE(this)->normalManager != NULL);
1056
PRIVATE(this)->normalManager->setBackgroundIndex(idx);
1057
this->scheduleRedraw();
1061
This method returns the index of the background color for the scene.
1064
SoQtRenderArea::getBackgroundIndex(void) const
1066
assert(PRIVATE(this)->normalManager != NULL);
1067
return PRIVATE(this)->normalManager->getBackgroundIndex();
1070
// *************************************************************************
1073
This method sets the index of the background for the overlay scene.
1076
SoQtRenderArea::setOverlayBackgroundIndex(int idx)
1078
assert(PRIVATE(this)->overlayManager != NULL);
1079
PRIVATE(this)->overlayManager->setBackgroundIndex(idx);
1080
this->scheduleOverlayRedraw();
1084
This method returns the index of the background for the overlay scene.
1087
SoQtRenderArea::getOverlayBackgroundIndex(void) const
1089
assert(PRIVATE(this)->overlayManager != NULL);
1090
return PRIVATE(this)->overlayManager->getBackgroundIndex();
1093
// *************************************************************************
1096
This method sets the colormap for the scene.
1099
SoQtRenderArea::setColorMap(int start, int num, const SbColor * colors)
1101
delete [] PRIVATE(this)->normalColormap;
1102
PRIVATE(this)->normalColormapStart = start;
1103
PRIVATE(this)->normalColormapSize = num;
1104
PRIVATE(this)->normalColormap = new SbColor [ num ];
1105
for (int i = 0; i < num; i++)
1106
PRIVATE(this)->normalColormap[i] = colors[i];
1107
this->scheduleRedraw();
1111
This method sets the colormap for the overlay scene.
1114
SoQtRenderArea::setOverlayColorMap(int start, int num,
1115
const SbColor * colors)
1117
delete [] PRIVATE(this)->overlayColormap;
1118
PRIVATE(this)->overlayColormapStart = start;
1119
PRIVATE(this)->overlayColormapSize = num;
1120
PRIVATE(this)->overlayColormap = new SbColor [ num ];
1121
for (int i = 0; i < num; i++) {
1122
PRIVATE(this)->overlayColormap[i] = colors[i];
1124
this->scheduleOverlayRedraw();
1127
// *************************************************************************
1130
This method sets the viewport region.
1133
SoQtRenderArea::setViewportRegion(const SbViewportRegion & region)
1135
if (region.getWindowSize()[0] == -1) return;
1137
#if SOQT_DEBUG && 0 // debug
1138
SoDebugError::postInfo("SoQtRenderArea::setViewportRegion",
1140
region.getWindowSize()[0],
1141
region.getWindowSize()[1]);
1144
PRIVATE(this)->normalManager->setViewportRegion(region);
1145
PRIVATE(this)->overlayManager->setViewportRegion(region);
1146
this->scheduleRedraw();
1150
This method returns the viewport region.
1152
const SbViewportRegion &
1153
SoQtRenderArea::getViewportRegion(void) const
1155
assert(PRIVATE(this)->normalManager != NULL);
1156
return PRIVATE(this)->normalManager->getGLRenderAction()->getViewportRegion();
1159
// *************************************************************************
1162
This method sets the transparency type to be used for the scene.
1165
SoQtRenderArea::setTransparencyType(SoGLRenderAction::TransparencyType type)
1167
assert(PRIVATE(this)->normalManager != NULL);
1168
PRIVATE(this)->normalManager->getGLRenderAction()->setTransparencyType(type);
1169
PRIVATE(this)->overlayManager->getGLRenderAction()->setTransparencyType(type);
1170
this->scheduleRedraw();
1174
This method returns the transparency type used for the scene.
1176
SoGLRenderAction::TransparencyType
1177
SoQtRenderArea::getTransparencyType(void) const
1179
assert(PRIVATE(this)->normalManager != NULL);
1180
return PRIVATE(this)->normalManager->getGLRenderAction()->getTransparencyType();
1183
// *************************************************************************
1186
This method sets the antialiasing used for the scene.
1188
The \a smoothing flag signifies whether or not line and point
1189
aliasing should be turned on. See documentation of
1190
SoGLRenderAction::setSmoothing(), which will be called from this
1193
\a numPasses gives the number of re-renderings to do of the scene,
1194
blending together the results from slight "jitters" of the camera
1195
view, into the OpenGL accumulation buffer. For further information,
1196
see documentation of SoGLRenderAction::setNumPasses() and
1197
SoQtGLWidget::setAccumulationBuffer().
1200
SoQtRenderArea::setAntialiasing(SbBool smoothing, int numPasses)
1202
// FIXME: is this really necessary? I think we should either ignore
1203
// the call or store values for later migration if the scenemanager
1204
// instance(s) haven't been made yet. 20010331 mortene.
1205
assert(PRIVATE(this)->normalManager != NULL);
1207
// Instead of piping the call further to
1208
// SoSceneManager::setAntialiasing(), we duplicate the code found in
1209
// that function. The reason for this is that we want to work around
1210
// a bug found in SGI Inventor, where they define the
1211
// setAntialiasing() method, but doesn't actually implement it. So
1212
// we don't use it to avoid a linker error for those compiling So*
1213
// libraries on top of the older SGI Inventor versions with this
1216
// We should perhaps throw in a configure check for the
1217
// SoSceneManager::setAntialiasing() method and only activate this
1218
// code when actually needed?
1221
SoSceneManager * mgrs[MGRS] = { PRIVATE(this)->normalManager,
1222
PRIVATE(this)->overlayManager };
1223
for (int i=0; i < MGRS; i++) {
1224
SoGLRenderAction * glra = mgrs[i]->getGLRenderAction();
1226
glra->setSmoothing(smoothing);
1227
glra->setNumPasses(numPasses);
1231
this->scheduleRedraw();
1235
This method returns the antialiasing used for the scene.
1238
SoQtRenderArea::getAntialiasing(SbBool & smoothing, int & numPasses) const
1240
// FIXME: there's an API design flaw here, as it is assumed that the
1241
// antialiasing setting for the renderaction in the "normal"
1242
// rendering context always matches what is the case for the
1243
// renderaction in the overlay manager. This is not necessarily
1244
// true. Could be solved by an additional argument to
1245
// getAntialiasing(): a boolean indicator on whether or not we want
1246
// the overlay context with a default value (false) to keep API
1247
// compatibility. 20010331 mortene.
1249
assert(PRIVATE(this)->normalManager != NULL);
1251
// About why we don't use SoSceneManager::getAntialiasing()
1252
// directly, see comment in SoGuiRenderArea::setAntiAliasing().
1253
SoGLRenderAction * glra = PRIVATE(this)->normalManager->getGLRenderAction();
1254
smoothing = glra->isSmoothing();
1255
numPasses = glra->getNumPasses();
1259
This method sets whether the render buffer should be cleared before
1262
The first argument specifies whether or not to clear out the pixels
1263
in the buffer, the second argument specifies whether or not the
1264
z-buffer values should be cleared between renderings.
1266
Setting the first argument to \c FALSE can for instance be used when
1267
you want to clear out the buffer yourself, for instance by drawing a
1268
background image "under" the 3D scene rendered by Coin / Inventor.
1271
SoQtRenderArea::setClearBeforeRender(SbBool enable, SbBool zbEnable)
1273
PRIVATE(this)->clear = enable;
1274
PRIVATE(this)->clearZBuffer = zbEnable;
1276
this->scheduleRedraw();
1280
This method returns whether the render buffer is cleared before each
1284
SoQtRenderArea::isClearBeforeRender(void) const
1286
return PRIVATE(this)->clear;
1290
This method returns whether the render buffer's Z buffer is cleared
1294
SoQtRenderArea::isClearZBufferBeforeRender(void) const
1296
return PRIVATE(this)->clearZBuffer;
1300
This method sets whether the overlay render buffer should be cleared
1301
before each render or not.
1304
SoQtRenderArea::setClearBeforeOverlayRender(SbBool enable)
1306
PRIVATE(this)->clearOverlay = enable;
1307
this->scheduleOverlayRedraw();
1311
This method returns whether the overlay render buffer is cleared
1312
before each redraw or not.
1315
SoQtRenderArea::isClearBeforeOverlayRender(void) const
1317
return PRIVATE(this)->clearOverlay;
1321
This method sets whether redrawing should be handled automatically
1322
or not when data in the scenegraph changes.
1324
The default setting causes the renderarea to automatically trigger a
1325
redraw of the scenegraph contents.
1328
SoQtRenderArea::setAutoRedraw(SbBool enable)
1331
PRIVATE(this)->normalManager->setRenderCallback(SoQtRenderAreaP::renderCB, this);
1332
PRIVATE(this)->overlayManager->setRenderCallback(SoQtRenderAreaP::renderCB, this);
1335
PRIVATE(this)->normalManager->setRenderCallback(NULL, NULL);
1336
PRIVATE(this)->overlayManager->setRenderCallback(NULL, NULL);
1339
// We can not use the render callback ptr as a flag, as the render
1340
// callback pointer will be set upon expose events and forced
1341
// redraws -- and autoRedraw is then used to remember that the
1342
// pointer should be set back to NULL again after redraw.
1343
PRIVATE(this)->autoRedraw = enable;
1347
This method returns whether redrawing is handled automatically
1351
SoQtRenderArea::isAutoRedraw(void) const
1353
return PRIVATE(this)->autoRedraw;
1357
This method sets the redraw priority.
1360
SoQtRenderArea::setRedrawPriority(uint32_t priority)
1362
PRIVATE(this)->normalManager->setRedrawPriority(priority);
1363
PRIVATE(this)->overlayManager->setRedrawPriority(priority);
1367
This method returns the redraw priority.
1370
SoQtRenderArea::getRedrawPriority(void) const
1372
assert(PRIVATE(this)->normalManager != NULL);
1373
return PRIVATE(this)->normalManager->getRedrawPriority();
1377
This function returns the default redraw priority.
1380
SoQtRenderArea::getDefaultRedrawPriority(void)
1382
return SoSceneManager::getDefaultRedrawPriority();
1386
This method causes the immediate rendering of the scene, by calling
1387
SoQtRenderArea::redraw().
1390
SoQtRenderArea::render(void)
1396
This method renders the overlay scene.
1399
SoQtRenderArea::renderOverlay(void)
1401
this->redrawOverlay();
1405
This method schedules a redraw to happen at a later time (when the
1406
application has processed it's other events first).
1409
SoQtRenderArea::scheduleRedraw(void)
1411
#if SOQT_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug
1412
SoDebugError::postInfo("SoQtRenderArea::scheduleRedraw",
1416
assert(PRIVATE(this)->normalManager != NULL);
1417
// In case autoRedraw is OFF. The callback pointer will be reset to
1418
// NULL in renderCB() if autoRedraw is OFF.
1419
PRIVATE(this)->normalManager->setRenderCallback(SoQtRenderAreaP::renderCB, this);
1420
PRIVATE(this)->normalManager->scheduleRedraw(); // Redraw when idle.
1424
This method schedules a redraw of the overlay scene.
1427
SoQtRenderArea::scheduleOverlayRedraw(void)
1429
assert(PRIVATE(this)->overlayManager != NULL);
1430
// In case autoRedraw is OFF. The callback pointer will be reset to
1431
// NULL in renderCB() if autoRedraw is OFF.
1432
PRIVATE(this)->overlayManager->setRenderCallback(SoQtRenderAreaP::renderCB, this);
1433
PRIVATE(this)->overlayManager->scheduleRedraw(); // Redraw when idle.
1436
#ifndef DOXYGEN_SKIP_THIS
1438
SoQtRenderAreaP::replaceSoSelectionMonitor(SoSelection * newsel,
1439
SoSelection * oldsel) const
1441
if (newsel) { newsel->ref(); }
1444
oldsel->removeChangeCallback(SoQtRenderAreaP::selection_redraw_cb,
1450
newsel->addChangeCallback(SoQtRenderAreaP::selection_redraw_cb,
1454
#endif // DOXYGEN_SKIP_THIS
1456
// FIXME: the interface below is badly designed, see the comment in
1457
// the function documentation. 20001002 mortene.
1460
Do automatic redraw of the scenegraph when a selection under the
1461
SoSelection node is changed.
1463
Pass \c NULL to deactivate.
1465
(Only one SoSelection node can be monitored at any given time. This
1466
is obviously a rather silly design flaw. We choose to match the
1467
original Inventor API here, but this will probably change in the
1468
next major revision of the library.)
1471
SoQtRenderArea::redrawOnSelectionChange(SoSelection * selection)
1473
PRIVATE(this)->replaceSoSelectionMonitor(selection, PRIVATE(this)->normalselection);
1474
PRIVATE(this)->normalselection = selection;
1478
Do automatic redraw of the scenegraph in the overlay planes when a
1479
selection under the SoSelection node is changed.
1481
Pass \c NULL to deactivate.
1483
\sa SoQtRenderArea::redrawOnSelectionChange()
1486
SoQtRenderArea::redrawOverlayOnSelectionChange(SoSelection * selection)
1488
PRIVATE(this)->replaceSoSelectionMonitor(selection, PRIVATE(this)->overlayselection);
1489
PRIVATE(this)->overlayselection = selection;
1493
This method sets the render area event callback.
1496
SoQtRenderArea::setEventCallback(SoQtRenderAreaEventCB * func,
1499
PRIVATE(this)->appeventhandler = func;
1500
PRIVATE(this)->appeventhandlerdata = user;
1504
This method sets the normal scene SoSceneManager object.
1507
SoQtRenderArea::setSceneManager(SoSceneManager * manager)
1509
assert(PRIVATE(this)->normalManager != NULL);
1510
PRIVATE(this)->normalManager->setRenderCallback(NULL, NULL);
1511
delete PRIVATE(this)->normalManager;
1512
PRIVATE(this)->normalManager = manager;
1516
This method returns the normal scene SoSceneManager object.
1518
Having a reference to the SoSceneManager instance is useful for
1519
getting at the \e real root node of the rendering scenegraph,
1520
including camera, headlight and miscellaneous drawstyle nodes. The
1521
getSceneGraph() method will only return the \e user scenegrah for
1522
SoQtRenderArea subclass SoQtViewer and further subclasses. The
1523
reason this is not always what you want is because certain actions
1524
(like the SoRayPickAction) needs to traverse a valid camera if it
1525
should work as expected.
1527
If you need to get a pointer to the \e real root node use this
1528
method to get the SoSceneManager instance reference used by the
1529
SoQtRenderArea, then use SoSceneManager::getSceneGraph() to get
1530
the root node Coin uses for rendering.
1533
SoQtRenderArea::getSceneManager(void) const
1535
return PRIVATE(this)->normalManager;
1539
This method sets the overlay scene SoSceneManager object.
1542
SoQtRenderArea::setOverlaySceneManager(SoSceneManager * manager)
1544
PRIVATE(this)->overlayManager = manager;
1548
This method returns the overlay scene SoSceneManager object.
1551
SoQtRenderArea::getOverlaySceneManager(void) const
1553
return PRIVATE(this)->overlayManager;
1557
This method sets the SoGLRenderAction object for the normal scene.
1560
SoQtRenderArea::setGLRenderAction(SoGLRenderAction * action)
1562
assert(PRIVATE(this)->normalManager != NULL);
1563
PRIVATE(this)->normalManager->setGLRenderAction(action);
1564
// Force an update of the SoGLRenderAction to the correct
1565
// updatearea, aspectratio, etc.
1566
this->sizeChanged(this->getSize());
1570
This method returns the SoGLRenderAction object for the normal scene.
1573
SoQtRenderArea::getGLRenderAction(void) const
1575
assert(PRIVATE(this)->normalManager != NULL);
1576
return PRIVATE(this)->normalManager->getGLRenderAction();
1580
This method sets the SoGLRenderAction object for rendering the
1584
SoQtRenderArea::setOverlayGLRenderAction(SoGLRenderAction * action)
1586
assert(PRIVATE(this)->overlayManager != NULL);
1587
PRIVATE(this)->overlayManager->setGLRenderAction(action);
1591
This method returns the SoGLRenderAction object for the overlay scene
1595
SoQtRenderArea::getOverlayGLRenderAction(void) const
1597
assert(PRIVATE(this)->overlayManager != NULL);
1598
return PRIVATE(this)->overlayManager->getGLRenderAction();
1602
This method is called from the render() method and takes care of
1603
setting up the context for OpenGL rendering (by making the OpenGL
1604
canvas the current context and specifying either the front or back
1605
buffer for rendering, depending on whether we're in singlebuffer or
1608
After setting up the OpenGL context, it calls actualRedraw() for the
1609
actual scenegraph rendering to take place.
1611
Finally, the OpenGL buffers are either swapped back-to-front (for
1612
doublebuffering) or flushed (for singlebuffering), and our OpenGL
1613
context is unlocked.
1615
The application programmer may override this method if extreme
1616
low-level control of the rendering process is necessary. Usually,
1617
you should be able to get away with overriding actualRedraw() for
1618
special cases, though.
1621
SoQtRenderArea::redraw(void)
1623
#if SOQT_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug
1624
SoDebugError::postInfo("SoQtRenderArea::redraw",
1625
"start (isVisible=%s waitForExpose=%s)",
1626
this->isVisible() ? "TRUE" : "FALSE",
1627
this->waitForExpose ? "TRUE" : "FALSE");
1630
if (! this->isVisible() || !this->hasNormalGLArea() || this->waitForExpose)
1632
this->glLockNormal(); // this makes the GL context "current"
1635
! this->isDoubleBuffer() ||
1636
this->isDrawToFrontBufferEnable();
1638
glDrawBuffer(drawfront ? GL_FRONT : GL_BACK);
1640
this->actualRedraw();
1642
if (!drawfront) { this->glSwapBuffers(); }
1643
else { this->glFlushBuffer(); }
1644
this->glUnlockNormal();
1646
#if SOQT_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug
1647
SoDebugError::postInfo("SoQtRenderArea::render", "done");
1651
// Note: the following function documentation block will also be used
1652
// for all the miscellaneous viewer subclasses, so keep it general.
1654
This method instantly redraws the normal (non-overlay) scenegraph by
1655
calling SoSceneManager::render().
1657
Subclasses may override this method to add their own rendering
1658
before or after Coin renders it's scenegraph.
1660
The following is a complete example that demonstrates one way of
1661
adding both a background image and foreground (overlay) geometry to
1662
the "normal" rendering:
1665
// This example shows how to put a permanent background image on your
1666
// viewer canvas, below the 3D graphics, plus overlay foreground
1667
// geometry. Written by mortene. Copyright Systems in Motion 2002.
1669
// *************************************************************************
1671
#include <Inventor/Qt/SoQt.h>
1672
#include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
1673
#include <Inventor/nodes/SoBaseColor.h>
1674
#include <Inventor/nodes/SoCone.h>
1675
#include <Inventor/nodes/SoCube.h>
1676
#include <Inventor/nodes/SoImage.h>
1677
#include <Inventor/nodes/SoLightModel.h>
1678
#include <Inventor/nodes/SoOrthographicCamera.h>
1679
#include <Inventor/nodes/SoRotationXYZ.h>
1680
#include <Inventor/nodes/SoSeparator.h>
1681
#include <Inventor/nodes/SoTranslation.h>
1685
// *************************************************************************
1687
class MyExaminerViewer : public SoQtExaminerViewer {
1690
MyExaminerViewer(QWidget * parent, const char * filename);
1691
~MyExaminerViewer();
1694
virtual void actualRedraw(void);
1697
SoSeparator * bckgroundroot;
1698
SoSeparator * foregroundroot;
1699
SoRotationXYZ * arrowrotation;
1702
MyExaminerViewer::MyExaminerViewer(QWidget * parent, const char * filename)
1703
: SoQtExaminerViewer(parent)
1705
// Coin should not clear the pixel-buffer, so the background image
1707
this->setClearBeforeRender(FALSE, TRUE);
1710
// Set up background scenegraph with image in it.
1712
this->bckgroundroot = new SoSeparator;
1713
this->bckgroundroot->ref();
1715
SoOrthographicCamera * cam = new SoOrthographicCamera;
1716
cam->position = SbVec3f(0, 0, 1);
1718
// SoImage will be at z==0.0.
1719
cam->nearDistance = 0.5;
1720
cam->farDistance = 1.5;
1722
SoImage * img = new SoImage;
1723
img->vertAlignment = SoImage::HALF;
1724
img->horAlignment = SoImage::CENTER;
1725
img->filename = filename;
1727
this->bckgroundroot->addChild(cam);
1728
this->bckgroundroot->addChild(img);
1730
// Set up foreground, overlayed scenegraph.
1732
this->foregroundroot = new SoSeparator;
1733
this->foregroundroot->ref();
1735
SoLightModel * lm = new SoLightModel;
1736
lm->model = SoLightModel::BASE_COLOR;
1738
SoBaseColor * bc = new SoBaseColor;
1739
bc->rgb = SbColor(1, 1, 0);
1741
cam = new SoOrthographicCamera;
1742
cam->position = SbVec3f(0, 0, 5);
1744
cam->nearDistance = 0;
1745
cam->farDistance = 10;
1747
const double ARROWSIZE = 2.0;
1749
SoTranslation * posit = new SoTranslation;
1750
posit->translation = SbVec3f(-2.5 * ARROWSIZE, 1.5 * ARROWSIZE, 0);
1752
arrowrotation = new SoRotationXYZ;
1753
arrowrotation->axis = SoRotationXYZ::Z;
1755
SoTranslation * offset = new SoTranslation;
1756
offset->translation = SbVec3f(ARROWSIZE/2.0, 0, 0);
1758
SoCube * cube = new SoCube;
1759
cube->width = ARROWSIZE;
1760
cube->height = ARROWSIZE/15.0;
1762
this->foregroundroot->addChild(cam);
1763
this->foregroundroot->addChild(lm);
1764
this->foregroundroot->addChild(bc);
1765
this->foregroundroot->addChild(posit);
1766
this->foregroundroot->addChild(arrowrotation);
1767
this->foregroundroot->addChild(offset);
1768
this->foregroundroot->addChild(cube);
1771
MyExaminerViewer::~MyExaminerViewer()
1773
this->bckgroundroot->unref();
1774
this->foregroundroot->unref();
1778
MyExaminerViewer::actualRedraw(void)
1780
// Must set up the OpenGL viewport manually, as upon resize
1781
// operations, Coin won't set it up until the SoGLRenderAction is
1782
// applied again. And since we need to do glClear() before applying
1784
const SbViewportRegion vp = this->getViewportRegion();
1785
SbVec2s origin = vp.getViewportOriginPixels();
1786
SbVec2s size = vp.getViewportSizePixels();
1787
glViewport(origin[0], origin[1], size[0], size[1]);
1789
const SbColor col = this->getBackgroundColor();
1790
glClearColor(col[0], col[1], col[2], 0.0f);
1791
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1793
// Render our scenegraph with the image.
1794
SoGLRenderAction * glra = this->getGLRenderAction();
1795
glra->apply(this->bckgroundroot);
1798
// Render normal scenegraph.
1799
SoQtExaminerViewer::actualRedraw();
1802
// Increase arrow angle with 1/1000 � every frame.
1803
arrowrotation->angle = arrowrotation->angle.getValue() + (0.001 / M_PI * 180);
1804
// Render overlay front scenegraph.
1805
glClear(GL_DEPTH_BUFFER_BIT);
1806
glra->apply(this->foregroundroot);
1809
// *************************************************************************
1812
main(int argc, char ** argv)
1815
(void)fprintf(stderr, "\n\n\tUsage: %s <image-filename>\n\n", argv[0]);
1819
QWidget * window = SoQt::init(argv[0]);
1821
MyExaminerViewer * viewer = new MyExaminerViewer(window, argv[1]);
1823
viewer->setSceneGraph(new SoCone);
1833
// *************************************************************************
1837
SoQtRenderArea::actualRedraw(void)
1839
assert(PRIVATE(this)->normalManager != NULL);
1840
if ( !this->isVisible() ) return;
1841
PRIVATE(this)->normalManager->render(PRIVATE(this)->clear, PRIVATE(this)->clearZBuffer);
1845
This method redraws the overlay scene.
1848
SoQtRenderArea::redrawOverlay(void)
1850
if (!this->isVisible() || this->waitForExpose || !this->hasOverlayGLArea()) {
1854
this->glLockOverlay();
1855
this->actualOverlayRedraw();
1856
this->glFlushBuffer();
1857
this->glUnlockOverlay();
1861
This method renders the overlay scene.
1864
SoQtRenderArea::actualOverlayRedraw(void)
1866
assert(PRIVATE(this)->overlayManager != NULL);
1867
if (! this->isVisible()) return;
1868
PRIVATE(this)->overlayManager->render(PRIVATE(this)->clearOverlay,
1869
PRIVATE(this)->clearZBuffer);
1873
This method is invoked to initialize the normal graphics.
1876
SoQtRenderArea::initGraphic(void)
1878
SoSceneManager * mgr = this->getSceneManager();
1880
mgr->reinitialize();
1881
mgr->setRGBMode(this->isRGBMode());
1883
SoGLRenderAction * renderaction = mgr->getGLRenderAction();
1884
renderaction->setCacheContext(SoAny::si()->getSharedCacheContextId(this));
1885
SbBool isdirect = SoGuiGLWidgetP::isDirectRendering(this);
1886
renderaction->setRenderingIsRemote(!isdirect);
1888
// FIXME: if not RGB mode, load colormap. pederb.
1890
inherited::initGraphic();
1894
This method is invoked to initialize the overlay graphics.
1897
SoQtRenderArea::initOverlayGraphic(void)
1899
SoSceneManager * mgr = this->getOverlaySceneManager();
1901
mgr->reinitialize();
1902
// FIXME: does overlays really _have_ to be in colorindex mode?
1903
// 20020916 mortene.
1904
mgr->setRGBMode(FALSE);
1906
SoGLRenderAction * renderaction = mgr->getGLRenderAction();
1907
SbBool isdirect = SoGuiGLWidgetP::isDirectRendering(this);
1908
renderaction->setRenderingIsRemote(!isdirect);
1909
// FIXME: shouldn't we also setCacheContext() on the renderaction?
1910
// 20020916 mortene.
1912
// FIXME: if not RGB mode, load colormap. pederb.
1914
// FIXME: shouldn't we do inherited::initOverlayGraphic() ? 20010831 mortene.
1919
SoQtRenderArea::sizeChanged(const SbVec2s & size)
1922
SoDebugError::postInfo("SoQtRenderArea::sizeChanged",
1923
"invoked, <%d, %d>", size[0], size[1]);
1924
#endif // SOQT_DEBUG
1926
SbVec2s newsize(size);
1931
assert(PRIVATE(this)->normalManager != NULL);
1932
assert(PRIVATE(this)->overlayManager != NULL);
1934
// Workaround for a bug in Qt/Mac 3.1.0 and 3.1.1 (which has been
1935
// confirmed fixed in 3.1.2):
1937
// If the OpenGL context overlaps with the QSizeGrip widget
1938
// (generated by default), resizing does not work any more. The
1939
// workaround is to leave 15 pixels at the lower border of the
1942
#if defined Q_WS_MAC && ((QT_VERSION == 0x030100) || (QT_VERSION == 0x030101))
1944
// Environment variable to override Qt/Mac 3.1.x workarounds.
1945
const char * forcenoresizeworkaround =
1946
SoAny::si()->getenv("FORCE_NO_QTMAC_31_RESIZE_WORKAROUND");
1947
if (!forcenoresizeworkaround || (atoi(forcenoresizeworkaround) == 0)) {
1949
if (this->getTypeId() == SoQtRenderArea::getClassTypeId()) {
1950
// SoQtRenderArea used as standalone component
1951
newsize -= SbVec2s(0, 15);
1953
// spit out a warning that this is a Qt/Mac bug, not an SoQt problem
1954
const char * env = SoAny::si()->getenv("SOQT_NO_QTMAC_BUG_WARNINGS");
1955
if (!env || !atoi(env)) {
1956
SoDebugError::postWarning("SoQtRenderArea::sizeChanged",
1957
"\nThis version of Qt/Mac contains a bug "
1958
"that makes it necessary to leave the\n"
1959
"lowermost 15 pixels of the viewer window "
1960
"blank. Set the environment variable\n"
1961
"FORCE_NO_QTMAC_31_RESIZE_WORKAROUND=1 to "
1962
"override this workaround. \n"
1963
"You can turn off warnings about Qt/Mac "
1964
"bugs permanently by setting \n"
1965
"SOQT_NO_QTMAC_BUG_WARNINGS=1.\n");
1972
this->setGLSize(newsize);
1973
const SbVec2s glsize = this->getGLSize();
1977
SoDebugError::postInfo("SoQtRenderArea::sizeChanged",
1978
"glsize==<%d, %d>", glsize[0], glsize[1]);
1979
#endif // SOQT_DEBUG
1981
if (glsize[0] <= 0 || glsize[1] <= 0)
1984
this->setViewportRegion(SbViewportRegion(glsize));
1985
PRIVATE(this)->setDevicesWindowSize(glsize);
1987
// FIXME: aren't both these calls unnecessary as we set the full
1988
// viewportregion a few lines above this one? 20020103 mortene.
1989
PRIVATE(this)->normalManager->setWindowSize(glsize);
1990
PRIVATE(this)->normalManager->setSize(glsize);
1992
// FIXME: aren't both these calls unnecessary as we set the full
1993
// viewportregion a few lines above this one? 20020103 mortene.
1994
PRIVATE(this)->overlayManager->setWindowSize(glsize);
1995
PRIVATE(this)->overlayManager->setSize(glsize);
1997
inherited::sizeChanged(glsize);
1999
// this->scheduleRedraw(); // already done through setViewportRegion()
2002
// Documented in superclass.
2004
SoQtRenderArea::widgetChanged(QWidget * widget)
2006
PRIVATE(this)->normalManager->reinitialize();
2007
PRIVATE(this)->overlayManager->reinitialize();
2008
// FIXME: colorindex mode not supported yet, so this has no
2009
// effect. 20001121 mortene.
2011
PRIVATE(this)->normalManager->setRGBMode(this->isRGBMode());
2012
PRIVATE(this)->overlayManager->setRGBMode(this->isRGBMode());
2015
// FIXME: should also walk through all registered devices and do a
2016
// disable() on the old widget and enable() on the new one.
2017
// 20001121 mortene.
2020
// Documented in superclass.
2022
SoQtRenderArea::buildWidget(QWidget * parent)
2024
QWidget * widget = inherited::buildWidget(parent);
2026
if (PRIVATE(this)->devicelist != NULL) {
2027
const int num = PRIVATE(this)->devicelist->getLength();
2028
for (int i = 0; i < num; i++) {
2029
SoQtDevice * device = (SoQtDevice *) (*PRIVATE(this)->devicelist)[i];
2030
#ifdef __COIN_SOXT__
2031
device->enable(this->getGLWidget(),
2032
(SoXtEventHandler *) &SoQtGLWidget::eventHandler,
2035
device->enable(this->getGLWidget(),
2036
&SoQtGLWidgetP::eventHandler, (void *) this);
2044
// Documented in superclass.
2046
SoQtRenderArea::getDefaultWidgetName(void) const
2048
static const char defaultWidgetName[] = "SoQtWidgetName";
2049
return defaultWidgetName;
2052
// Documented in superclass.
2054
SoQtRenderArea::getDefaultTitle(void) const
2056
static const char defaultTitle[] = "Qt RenderArea";
2057
return defaultTitle;
2060
// Documented in superclass.
2062
SoQtRenderArea::getDefaultIconTitle(void) const
2064
static const char defaultIconTitle[] = "Qt RenderArea";
2065
return defaultIconTitle;
2068
// *************************************************************************
2071
Toolkit-native events are attempted converted to Coin-generic events
2072
in the SoQtRenderArea::processEvent() method. If this succeeds,
2073
they are forwarded to this method.
2075
This is a virtual method, and is overridden in it's subclasses to
2076
catch events of particular interest to the viewer classes, for
2079
Return \c TRUE iff the event was processed. If not it should be
2080
passed on further up in the inheritance hierarchy by the caller.
2081
This last point is extremely important to take note of if you are
2082
expanding the toolkit with your own viewer class.
2084
This method is not part of the original SGI InventorXt API. Note
2085
that you can still override the toolkit-native processEvent() method
2086
instead of this "generic" method.
2089
SoQtRenderArea::processSoEvent(const SoEvent * const event)
2091
if (PRIVATE(this)->overlayManager->processEvent(event)) { return TRUE; }
2092
if (PRIVATE(this)->normalManager->processEvent(event)) { return TRUE; }
2096
// *************************************************************************
2099
Overrides SoQtGLWidget::processEvent() to attempt to convert
2100
toolkit-native events to Coin-generic events. If this succeeds, the
2101
generic SoEvent is forwarded to SoQtRenderArea::processSoEvent().
2104
SoQtRenderArea::processEvent(QEvent * event)
2106
if (PRIVATE(this)->invokeAppCB(event)) { return; }
2108
const SoEvent * soevent = PRIVATE(this)->getSoEvent(event);
2110
if (soevent != NULL) {
2112
// Undocumented feature: there are several "magic" sequences of
2113
// keys when tapped into the rendering canvas which'll pop up a
2114
// dialog box with information about that particular feature.
2116
// See code comments behind "case" statements below for which
2117
// sequences are available so far.
2119
if (soevent->isOfType(SoKeyboardEvent::getClassTypeId())) {
2120
SoKeyboardEvent * ke = (SoKeyboardEvent *)soevent;
2121
if (ke->getState() == SoButtonEvent::UP) {
2122
char c = ke->getPrintableCharacter();
2123
switch (PRIVATE(this)->checkMagicSequences(c)) {
2124
case SoQtRenderAreaP::NONE:
2126
case SoQtRenderAreaP::OPENGL: // "glinfo"
2127
this->glLockNormal();
2128
PRIVATE(this)->showOpenGLDriverInformation();
2129
this->glUnlockNormal();
2131
case SoQtRenderAreaP::INVENTOR: // "ivinfo"
2132
PRIVATE(this)->showInventorInformation();
2134
case SoQtRenderAreaP::TOOLKIT: // "soinfo"
2135
PRIVATE(this)->showToolkitInformation();
2137
case SoQtRenderAreaP::DUMPSCENEGRAPH: // "dumpiv"
2138
PRIVATE(this)->dumpScenegraph();
2140
case SoQtRenderAreaP::DUMPCAMERAS: // "cameras"
2141
PRIVATE(this)->dumpCameras();
2143
case SoQtRenderAreaP::OFFSCREENGRAB: // "osgrab"
2144
PRIVATE(this)->offScreenGrab();
2147
assert(FALSE && "unknown debug key sequence");
2152
#endif // SOQT_DEBUG
2154
SbBool processed = this->processSoEvent(soevent);
2155
if (processed) return;
2158
inherited::processEvent(event);
2161
// *************************************************************************
2165
SoQtRenderArea::glScheduleRedraw(void)
2167
this->scheduleRedraw();
2168
if (this->hasOverlayGLArea() && this->getOverlaySceneGraph()) {
2169
this->scheduleOverlayRedraw();
2174
// *************************************************************************
2177
This method posts and processes an SoEvent object to the
2178
SoQtRenderArea-based component and returns the result value from the
2179
event handler. This is a synchronous operation.
2182
SoQtRenderArea::sendSoEvent(const SoEvent * event)
2184
return this->processSoEvent(event);
2187
// *************************************************************************