~ubuntu-branches/ubuntu/oneiric/soqt/oneiric

« back to all changes in this revision

Viewing changes to build/msvc6/src/Inventor/Qt/SoQtRenderArea.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2006-02-06 22:34:00 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060206223400-g69m5soqa4zh0gkc
Tags: 1.3.0-3
debian/control: update libsoqt-dev depends.  Closes: #351700.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**************************************************************************\
 
2
 *
 
3
 *  This file is part of the Coin 3D visualization library.
 
4
 *  Copyright (C) 1998-2005 by Systems in Motion.  All rights reserved.
 
5
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
17
 *  See <URL:http://www.coin3d.org/> for more information.
 
18
 *
 
19
 *  Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY.
 
20
 *  <URL:http://www.sim.no/>.
 
21
 *
 
22
\**************************************************************************/
 
23
 
 
24
// src/Inventor/Qt/SoQtRenderArea.cpp.  Generated from SoGuiRenderArea.cpp.in by configure.
 
25
 
 
26
/**************************************************************************\
 
27
 *
 
28
 *  A WORD OF ADVICE
 
29
 *
 
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.
 
34
 *
 
35
\**************************************************************************/
 
36
 
 
37
// *************************************************************************
 
38
 
 
39
/*!
 
40
  \class SoQtRenderArea Inventor/Qt/SoQtRenderArea.h
 
41
  \brief The SoQtRenderArea class adds scenegraph handling and event management.
 
42
  \ingroup components viewers
 
43
 
 
44
  The SoQtRenderArea class is a component that adds scenegraph
 
45
  management and input device event handling to the SoQtGLWidget
 
46
  component.
 
47
 
 
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.
 
51
 
 
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.
 
56
 
 
57
 
 
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.
 
61
 
 
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.
 
65
 
 
66
  Here's a complete, stand-alone example on how to set up an
 
67
  SoQtRenderArea with a scenegraph:
 
68
 
 
69
  \code
 
70
  #include <Inventor/Qt/SoQt.h>
 
71
  #include <Inventor/Qt/SoQtRenderArea.h>
 
72
  
 
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>
 
79
  
 
80
  // Set up a simple scenegraph, just for demonstration purposes.
 
81
  static SoSeparator *
 
82
  get_scene_graph(void)
 
83
  {
 
84
    SoSeparator * root = new SoSeparator;
 
85
  
 
86
    SoGroup * group = new SoGroup;
 
87
  
 
88
    SoRotor * rotor = new SoRotor;
 
89
    rotor->rotation = SbRotation(SbVec3f(0.2, 0.5, 0.9), M_PI/4.0);
 
90
    group->addChild(rotor);
 
91
  
 
92
    SoCube * cube = new SoCube;
 
93
    group->addChild(cube);
 
94
  
 
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);
 
102
  
 
103
    root->addChild(array);
 
104
    return root;
 
105
  }
 
106
  
 
107
  int
 
108
  main(int argc, char ** argv)
 
109
  {
 
110
    QWidget * window = SoQt::init(argv[0]);
 
111
  
 
112
    SoSeparator * root = new SoSeparator;
 
113
    root->ref();
 
114
  
 
115
    SoPerspectiveCamera * camera;
 
116
    root->addChild(camera = new SoPerspectiveCamera);
 
117
  
 
118
    root->addChild(new SoDirectionalLight);
 
119
  
 
120
    SoSeparator * userroot = get_scene_graph();
 
121
    root->addChild(userroot);
 
122
  
 
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));
 
127
    if (argc > 1) {
 
128
      renderarea->setTitle(argv[1]);
 
129
      renderarea->setIconTitle(argv[1]);
 
130
    }
 
131
    renderarea->show();
 
132
  
 
133
    SoQt::show(window);
 
134
    SoQt::mainLoop();
 
135
  
 
136
    delete renderarea;
 
137
    root->unref();
 
138
  
 
139
    return 0;
 
140
  }
 
141
  \endcode
 
142
*/
 
143
 
 
144
// *************************************************************************
 
145
 
 
146
#include <Inventor/Qt/SoQtRenderArea.h>
 
147
 
 
148
#include <string.h> // strchr()
 
149
 
 
150
#ifdef HAVE_CONFIG_H
 
151
#include <config.h>
 
152
#endif // HAVE_CONFIG_H
 
153
 
 
154
#if SOQT_DEBUG // For the "soinfo" debugging backdoor.
 
155
#include <qgl.h>
 
156
#include <qapplication.h>
 
157
#endif // SOQT_DEBUG
 
158
 
 
159
#include <Inventor/Qt/common/gl.h> // glDrawBuffer()
 
160
 
 
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>
 
171
 
 
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
 
181
 
 
182
#include <Inventor/Qt/SoQtGLWidgetP.h>
 
183
#include <Inventor/Qt/SoAny.h>
 
184
 
 
185
#define RENDERAREA_DEBUG_REDRAWS 0
 
186
 
 
187
#define PRIVATE(obj) ((obj)->pimpl)
 
188
#define PUBLIC(obj) ((obj)->pub)
 
189
 
 
190
// *************************************************************************
 
191
 
 
192
SOQT_OBJECT_SOURCE(SoQtRenderArea);
 
193
 
 
194
// *************************************************************************
 
195
 
 
196
#ifndef DOXYGEN_SKIP_THIS
 
197
 
 
198
class SoQtRenderAreaP {
 
199
public:
 
200
 
 
201
  SoQtRenderAreaP(class SoQtRenderArea * pub);
 
202
  ~SoQtRenderAreaP(void);
 
203
 
 
204
  SbBool clear;
 
205
  SbBool clearZBuffer;
 
206
  SbBool clearOverlay;
 
207
 
 
208
  SoSceneManager * normalManager;
 
209
  SoSceneManager * overlayManager;
 
210
 
 
211
  SbColor * normalColormap;
 
212
  int normalColormapSize;
 
213
  int normalColormapStart;
 
214
  SbColor * overlayColormap;
 
215
  int overlayColormapSize;
 
216
  int overlayColormapStart;
 
217
 
 
218
  SbPList * devicelist;
 
219
 
 
220
  struct {
 
221
    SoQtKeyboard * keyboard;
 
222
    SoQtMouse * mouse;
 
223
  } devices;
 
224
 
 
225
  SbBool autoRedraw;
 
226
 
 
227
  void replaceSoSelectionMonitor(SoSelection * newsel, SoSelection * oldsel) const;
 
228
  SoSelection * normalselection;
 
229
  SoSelection * overlayselection;
 
230
 
 
231
  static const int GL_DEFAULT_MODE;
 
232
 
 
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);
 
237
 
 
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);
 
247
 
 
248
  SbBool invokeAppCB(QEvent * event);
 
249
  const SoEvent * getSoEvent(QEvent * event);
 
250
 
 
251
  SoQtRenderAreaEventCB * appeventhandler;
 
252
  void * appeventhandlerdata;
 
253
 
 
254
private:
 
255
  SoQtRenderArea * pub; // public interface class
 
256
  SbString currentinput; // For the OpenGL info-window hack.
 
257
};
 
258
 
 
259
const int SoQtRenderAreaP::GL_DEFAULT_MODE = (SO_GL_RGB |
 
260
                                                 SO_GL_ZBUFFER |
 
261
                                                 SO_GL_DOUBLE );
 
262
 
 
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__
 
268
 
 
269
// Note: assumes a valid current OpenGL context.
 
270
void
 
271
SoQtRenderAreaP::showOpenGLDriverInformation(void)
 
272
{
 
273
#if DEBUGGING_EGGS
 
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);
 
278
 
 
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   ";
 
283
    
 
284
  SbString exts = (const char *)extensions;
 
285
  const char * p;
 
286
  int count = 0;
 
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);
 
292
    count++;
 
293
    if (count == 4) { // number of extensions listed on each line
 
294
      info += "\n   ";
 
295
      count = 0;
 
296
    }
 
297
  }
 
298
  if (exts.getLength() > 0) { info += "\n   "; info += exts; }
 
299
  info += "\"\n";
 
300
 
 
301
  // FIXME: should also show available GLX / WGL / AGL
 
302
  // extensions. 20020802 mortene.
 
303
 
 
304
  // Misc implementation info
 
305
  {
 
306
    SbVec2f range;
 
307
    float granularity;
 
308
    PUBLIC(this)->getPointSizeLimits(range, granularity);
 
309
 
 
310
    SbString s;
 
311
    s.sprintf("glPointSize(): range=[%f, %f], granularity=%f\n",
 
312
              range[0], range[1], granularity);
 
313
    info += s;
 
314
 
 
315
 
 
316
    PUBLIC(this)->getLineWidthLimits(range, granularity);
 
317
 
 
318
    s.sprintf("glLineWidth(): range=[%f, %f], granularity=%f\n",
 
319
              range[0], range[1], granularity);
 
320
    info += s;
 
321
 
 
322
    GLint depthbits[1];
 
323
    glGetIntegerv(GL_DEPTH_BITS, depthbits);
 
324
    s.sprintf("GL_DEPTH_BITS==%d\n", depthbits[0]);
 
325
    info += s;
 
326
 
 
327
    GLint colbits[4];
 
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]);
 
334
    info += s;
 
335
 
 
336
    GLint accumbits[4];
 
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]);
 
343
    info += s;
 
344
 
 
345
    GLint maxdims[2];
 
346
    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxdims);
 
347
    s.sprintf("GL_MAX_VIEWPORT_DIMS==<%d, %d>\n", maxdims[0], maxdims[1]);
 
348
    info += s;
 
349
 
 
350
    GLint texdim;
 
351
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texdim);
 
352
    s.sprintf("GL_MAX_TEXTURE_SIZE==%d\n", texdim);
 
353
    info += s;
 
354
 
 
355
    GLint maxlights;
 
356
    glGetIntegerv(GL_MAX_LIGHTS, &maxlights);
 
357
    s.sprintf("GL_MAX_LIGHTS==%d\n", maxlights);
 
358
    info += s;
 
359
 
 
360
    GLint maxplanes;
 
361
    glGetIntegerv(GL_MAX_CLIP_PLANES, &maxplanes);
 
362
    s.sprintf("GL_MAX_CLIP_PLANES==%d\n", maxplanes);
 
363
    info += s;
 
364
 
 
365
    // FIXME: other implementation specifics to print are
 
366
    //
 
367
    //  * maximum stack depths (attribute, modelview matrix, name,
 
368
    //    projection matrix, texture matrix)
 
369
    //
 
370
    //  * max display list nesting
 
371
    //
 
372
    //  * max 3D texture size (needs specific extension?)
 
373
    //
 
374
    // 20020802 mortene.
 
375
  }
 
376
 
 
377
  SbString s;
 
378
  s.sprintf("\n"
 
379
            "Rendering is %sdirect.\n",
 
380
            SoGuiGLWidgetP::isDirectRendering(PUBLIC(this)) ? "" : "in");
 
381
  info += s;
 
382
 
 
383
  SoQt::createSimpleErrorDialog(NULL, "OpenGL driver information",
 
384
                                    info.getString());
 
385
#endif // DEBUGGING_EGGS
 
386
}
 
387
 
 
388
void
 
389
SoQtRenderAreaP::showInventorInformation(void)
 
390
{
 
391
#if DEBUGGING_EGGS
 
392
  SbString info;
 
393
  info.sprintf("%s\n", SoDB::getVersion());
 
394
 
 
395
  // Display calculated maximum resolution of SbTime::getTimeOfDay().
 
396
  {
 
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;
 
402
    do {
 
403
      current = SbTime::getTimeOfDay();
 
404
      if (current.getValue() != last.getValue()) { ticks++; last = current; }
 
405
    } while (current < end);
 
406
    SbString s;
 
407
    s.sprintf("\nSbTime::getTimeOfDay() resolution: ~ %d Hz\n",
 
408
              (int)(((double)ticks) / DURATION));
 
409
    info += s;
 
410
  }
 
411
 
 
412
  // FIXME: dump list of available node classes? 20010927 mortene.
 
413
  SoQt::createSimpleErrorDialog(NULL, "Inventor implementation info",
 
414
                                    info.getString());
 
415
 
 
416
#endif // DEBUGGING_EGGS
 
417
}
 
418
 
 
419
void
 
420
SoQtRenderAreaP::showToolkitInformation(void)
 
421
{
 
422
#if DEBUGGING_EGGS
 
423
  SbString info = "SoQt version "; info += SOQT_VERSION; info += "\n";
 
424
#if SOQT_MAKE_DLL
 
425
  info += "Built as MSWindows DLL.\n";
 
426
#endif // !SOQT_MAKE_DLL
 
427
 
 
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.
 
431
 
 
432
#ifdef SOQT_INTERNAL
 
433
  // Qt implementation info.
 
434
  {
 
435
    SbString s;
 
436
    s.sprintf("\nQt version: %s\n", qVersion());
 
437
    info += s;
 
438
  }
 
439
#endif // SOQT_INTERNAL
 
440
 
 
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.
 
448
  //
 
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.)
 
453
  //
 
454
  // 20010927 mortene.
 
455
 
 
456
  // OpenGL canvas settings.
 
457
  {
 
458
    SbString s;
 
459
    s.sprintf("\nCurrent OpenGL canvas:\n"
 
460
              "         %sbuffer\n"
 
461
              "         drawing to %sbuffer\n"
 
462
              "         %s rendering%s\n"
 
463
              "         %s mode\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");
 
471
 
 
472
    // FIXME: information about the native OpenGL widget format?
 
473
    // 20010927 mortene.
 
474
 
 
475
    info += s;
 
476
  }
 
477
 
 
478
  // Underlying Inventor implementation.
 
479
  {
 
480
    SbString s;
 
481
    s.sprintf("\nInventor implementation: %s\n", SoDB::getVersion());
 
482
    info += s;
 
483
  }
 
484
 
 
485
  SoQt::createSimpleErrorDialog(NULL, "SoQt implementation info",
 
486
                                    info.getString());
 
487
#endif // DEBUGGING_EGGS
 
488
}
 
489
 
 
490
void
 
491
SoQtRenderAreaP::dumpScenegraph(void)
 
492
{
 
493
#ifdef DEBUGGING_EGGS
 
494
  SoOutput out;
 
495
  SbString filename = SbTime::getTimeOfDay().format();
 
496
  filename += "-dump.iv";
 
497
  SbBool ok = out.openFile(filename.getString());
 
498
  if (!ok) {
 
499
    SoDebugError::post("SoQtRenderAreaP::dumpScenegraph",
 
500
                       "couldn't open file '%s'", filename.getString());
 
501
    return;
 
502
  }
 
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
 
508
}
 
509
 
 
510
void
 
511
SoQtRenderAreaP::dumpCameras(void)
 
512
{
 
513
#ifdef DEBUGGING_EGGS
 
514
  const SbBool kitsearch = SoBaseKit::isSearchingChildren();
 
515
  SoBaseKit::setSearchingChildren(TRUE);
 
516
 
 
517
  SoSearchAction search;
 
518
  search.setType(SoCamera::getClassTypeId());
 
519
  search.setInterest(SoSearchAction::ALL);
 
520
  search.setSearchingAll(TRUE);
 
521
  search.apply(this->normalManager->getSceneGraph());
 
522
 
 
523
  SoBaseKit::setSearchingChildren(kitsearch);
 
524
 
 
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",
 
529
                         numcams);
 
530
 
 
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;
 
536
 
 
537
    const SbVec3f pos = cam->position.getValue();
 
538
    const SbRotation rot = cam->orientation.getValue();
 
539
    SbVec3f axis;
 
540
    float angle;
 
541
    rot.getValue(axis, angle);
 
542
 
 
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);
 
550
  }
 
551
#endif // DEBUGGING_EGGS
 
552
}
 
553
 
 
554
/*
 
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)
 
558
 
 
559
  Examples:
 
560
    export COIN_SOGRAB_GEOMETRY=1024x768
 
561
    export COIN_SOGRAB_FILENAME=c:\\grab%03d.png
 
562
 
 
563
*/
 
564
 
 
565
void
 
566
SoQtRenderAreaP::offScreenGrab(void)
 
567
{
 
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";
 
574
 
 
575
  /*
 
576
    FIXME:
 
577
 
 
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').
 
588
 
 
589
    20050606 larsa.
 
590
  */
 
591
 
 
592
  counter++;
 
593
  if ( maxwidth <= 0 ) {
 
594
    const char * env = 
 
595
      SoAny::si()->getenv("COIN_SOGRAB_GEOMETRY");
 
596
    if ( env ) {
 
597
      sscanf(env, "%dx%d", &maxwidth, &maxheight);
 
598
    }
 
599
    if ( (maxwidth <= 0) || !env ) {
 
600
      SbVec2s vp = PUBLIC(this)->getViewportRegion().getWindowSize();
 
601
      maxwidth = vp[0];
 
602
      maxheight = vp[1];
 
603
    }
 
604
  }
 
605
 
 
606
  if ( maxwidth <= 0 || maxheight <= 0 ) {
 
607
    SoDebugError::post("SoQtRenderAreaP::offScreenGrab",
 
608
                       "invalid geometry: %dx%d", maxwidth, maxheight);
 
609
    return;
 
610
  }
 
611
  SbVec2s vp = PUBLIC(this)->getViewportRegion().getWindowSize();
 
612
 
 
613
  const char * filenametpl =
 
614
    SoAny::si()->getenv("COIN_SOGRAB_FILENAME");
 
615
  if ( !filenametpl ) filenametpl = fallback_name;
 
616
 
 
617
  SbString filename;
 
618
  filename.sprintf(filenametpl, counter);
 
619
  const char * ext = strrchr(filename.getString(), '.');
 
620
  if ( !ext ) ext = fallback_ext;
 
621
  ext++;
 
622
 
 
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);
 
628
 
 
629
    osvp[1] = maxheight;
 
630
    osvp[0] = short(maxheight * onscaspect);
 
631
    if ( osvp[0] > maxwidth ) {
 
632
      osvp[0] = maxwidth;
 
633
      osvp[1] = short(maxwidth * (1.0f / onscaspect));
 
634
    }
 
635
  }
 
636
 
 
637
  SoOffscreenRenderer os(osvp);
 
638
  if ( !os.render(PUBLIC(this)->getSceneManager()->getSceneGraph()) ) {
 
639
    return;
 
640
  }
 
641
 
 
642
  if ( !os.writeToFile(filename, ext) && (strcmp(ext, "rgb") != 0) ) {
 
643
    SbString fname2;
 
644
    fname2.sprintf("%s.rgb", filename.getString());
 
645
    os.writeToRGB(fname2.getString());
 
646
  }
 
647
 
 
648
  SoDebugError::postInfo("SoQtRenderAreaP::offScreenGrab",
 
649
                         "wrote image #%d, %dx%d",
 
650
                         counter, osvp[0], osvp[1]);
 
651
#endif // DEBUGGING_EGGS
 
652
}
 
653
 
 
654
int
 
655
SoQtRenderAreaP::checkMagicSequences(const char c)
 
656
{
 
657
#if DEBUGGING_EGGS
 
658
  this->currentinput += c;
 
659
 
 
660
  if (0) { // handy for debugging keyboard handling
 
661
    SoDebugError::postInfo("SoQtRenderAreaP::checkMagicSequences",
 
662
                           "'%s'", this->currentinput.getString());
 
663
  }
 
664
 
 
665
  const int cl = this->currentinput.getLength();
 
666
 
 
667
  static const char * keyseq[] = {
 
668
    "glinfo", "ivinfo", "soinfo", "dumpiv", "cameras", "osgrab"
 
669
  };
 
670
  static const int id[] = {
 
671
    SoQtRenderAreaP::OPENGL,
 
672
    SoQtRenderAreaP::INVENTOR,
 
673
    SoQtRenderAreaP::TOOLKIT,
 
674
    SoQtRenderAreaP::DUMPSCENEGRAPH,
 
675
    SoQtRenderAreaP::DUMPCAMERAS,
 
676
    SoQtRenderAreaP::OFFSCREENGRAB
 
677
  };
 
678
 
 
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]) {
 
682
      return id[i];
 
683
    }
 
684
  }
 
685
 
 
686
  // Limit memory usage.
 
687
  if (cl > 1024) { this->currentinput = ""; }
 
688
#endif // DEBUGGING_EGGS
 
689
 
 
690
  return SoQtRenderAreaP::NONE;
 
691
}
 
692
 
 
693
// This method sets the window size data in all the connected device
 
694
// classes.
 
695
void
 
696
SoQtRenderAreaP::setDevicesWindowSize(const SbVec2s size)
 
697
{
 
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);
 
702
}
 
703
 
 
704
// *************************************************************************
 
705
 
 
706
void
 
707
SoQtRenderAreaP::renderCB(void * closure, SoSceneManager * manager)
 
708
{
 
709
  assert(closure && manager);
 
710
  SoQtRenderArea * thisptr = (SoQtRenderArea *) closure;
 
711
  if (manager == PRIVATE(thisptr)->normalManager) {
 
712
    thisptr->render();
 
713
  } else if (manager == PRIVATE(thisptr)->overlayManager) {
 
714
    thisptr->renderOverlay();
 
715
  } else {
 
716
#if SOQT_DEBUG
 
717
    SoDebugError::post("SoQtRenderAreaP::renderCB",
 
718
                       "invoked for unknown SoSceneManager (%p)", manager);
 
719
#endif // SOQT_DEBUG
 
720
    manager->setRenderCallback(NULL, NULL);
 
721
    return;
 
722
  }
 
723
 
 
724
  if (!thisptr->isAutoRedraw())
 
725
    manager->setRenderCallback(NULL, NULL);
 
726
}
 
727
 
 
728
// Callback for automatic redraw on SoSelection changes.
 
729
void
 
730
SoQtRenderAreaP::selection_redraw_cb(void * closure, SoSelection * sel)
 
731
{
 
732
  SoQtRenderArea * ra = (SoQtRenderArea *) closure;
 
733
  if (sel == PRIVATE(ra)->normalselection)
 
734
    ra->scheduleRedraw();
 
735
  else if (sel == PRIVATE(ra)->overlayselection)
 
736
    ra->scheduleOverlayRedraw();
 
737
  else
 
738
    assert(0 && "callback on unknown SoSelection node");
 
739
}
 
740
 
 
741
// Private class constructor.
 
742
SoQtRenderAreaP::SoQtRenderAreaP(SoQtRenderArea * api)
 
743
{
 
744
  PUBLIC(this) = api;
 
745
 
 
746
  this->normalManager = new SoSceneManager;
 
747
  this->overlayManager = new SoSceneManager;
 
748
 
 
749
  this->normalColormap = NULL;
 
750
  this->normalColormapSize = 0;
 
751
  this->overlayColormap = NULL;
 
752
  this->overlayColormapSize = 0;
 
753
 
 
754
  this->clear = TRUE;
 
755
  this->clearZBuffer = TRUE;
 
756
  this->clearOverlay = TRUE;
 
757
  this->autoRedraw = TRUE;
 
758
 
 
759
  this->normalselection = NULL;
 
760
  this->overlayselection = NULL;
 
761
 
 
762
  this->devices.mouse = NULL;
 
763
  this->devices.keyboard = NULL;
 
764
}
 
765
 
 
766
// Private class destructor.
 
767
SoQtRenderAreaP::~SoQtRenderAreaP()
 
768
{
 
769
  delete this->normalManager;
 
770
  delete this->overlayManager;
 
771
  delete [] this->normalColormap;
 
772
  delete [] this->overlayColormap;
 
773
}
 
774
 
 
775
// Common code for all constructors.
 
776
void
 
777
SoQtRenderAreaP::constructor(SbBool mouseInput,
 
778
                                SbBool keyboardInput,
 
779
                                SbBool build)
 
780
{
 
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?
 
788
  //
 
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
 
792
  // kosher?
 
793
  //
 
794
  // 20010831 mortene.
 
795
  this->overlayManager->getGLRenderAction()->setCacheContext(1);
 
796
 
 
797
  this->appeventhandler = NULL;
 
798
  this->appeventhandlerdata = NULL;
 
799
 
 
800
  this->devicelist = new SbPList;
 
801
 
 
802
  if (mouseInput) {
 
803
    this->devices.mouse = new SoQtMouse;
 
804
    PUBLIC(this)->registerDevice(this->devices.mouse);
 
805
  }
 
806
 
 
807
  if (keyboardInput) {
 
808
    this->devices.keyboard = new SoQtKeyboard;
 
809
    PUBLIC(this)->registerDevice(this->devices.keyboard);
 
810
  }
 
811
 
 
812
  if (! build) return;
 
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));
 
817
}
 
818
 
 
819
// This method invokes the application event handler, if one is set.
 
820
SbBool
 
821
SoQtRenderAreaP::invokeAppCB(QEvent * event)
 
822
{
 
823
  if (this->appeventhandler != NULL)
 
824
    return this->appeventhandler(this->appeventhandlerdata, event);
 
825
  return FALSE;
 
826
}
 
827
 
 
828
// This method returns an SoEvent * corresponding to the given \a
 
829
// event, or \c NULL if there are none.
 
830
const SoEvent *
 
831
SoQtRenderAreaP::getSoEvent(QEvent * event)
 
832
{
 
833
  if (!this->devicelist)
 
834
    return (SoEvent *) NULL;
 
835
 
 
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);
 
840
 
 
841
  return soevent;
 
842
}
 
843
 
 
844
#endif // DOXYGEN_SKIP_THIS
 
845
 
 
846
// *************************************************************************
 
847
 
 
848
/*!
 
849
  Public constructor.
 
850
*/
 
851
SoQtRenderArea::SoQtRenderArea(QWidget * parent,
 
852
                                     const char * name,
 
853
                                     SbBool embed,
 
854
                                     SbBool mouseInput,
 
855
                                     SbBool keyboardInput)
 
856
  : inherited(parent, name, embed, SoQtRenderAreaP::GL_DEFAULT_MODE, FALSE)
 
857
{
 
858
  PRIVATE(this) = new SoQtRenderAreaP(this);
 
859
  PRIVATE(this)->constructor(mouseInput, keyboardInput, TRUE);
 
860
}
 
861
 
 
862
/*!
 
863
  Protected constructor used by derived classes.
 
864
*/
 
865
SoQtRenderArea::SoQtRenderArea(QWidget * parent,
 
866
                                     const char * name,
 
867
                                     SbBool embed,
 
868
                                     SbBool mouseInput,
 
869
                                     SbBool keyboardInput,
 
870
                                     SbBool build)
 
871
  : inherited(parent, name, embed, SoQtRenderAreaP::GL_DEFAULT_MODE, FALSE)
 
872
{
 
873
  PRIVATE(this) = new SoQtRenderAreaP(this);
 
874
  PRIVATE(this)->constructor(mouseInput, keyboardInput, build);
 
875
}
 
876
 
 
877
/*!
 
878
  Destructor.
 
879
*/
 
880
SoQtRenderArea::~SoQtRenderArea()
 
881
{
 
882
  // Clean out any callbacks we may have registered with SoSelection
 
883
  // nodes.
 
884
  this->redrawOverlayOnSelectionChange(NULL);
 
885
  this->redrawOnSelectionChange(NULL);
 
886
 
 
887
  for (int i = PRIVATE(this)->devicelist->getLength() - 1; i >= 0; i--) {
 
888
    SoQtDevice * device = (SoQtDevice *) ((*PRIVATE(this)->devicelist)[i]);
 
889
    this->unregisterDevice(device);
 
890
    delete device;
 
891
  }
 
892
  delete PRIVATE(this)->devicelist;
 
893
  delete PRIVATE(this);
 
894
}
 
895
 
 
896
// *************************************************************************
 
897
 
 
898
/*!
 
899
  This method adds \a device to the list of devices handling events
 
900
  for this component.
 
901
*/
 
902
void
 
903
SoQtRenderArea::registerDevice(SoQtDevice * device)
 
904
{
 
905
  int idx = PRIVATE(this)->devicelist->find(device);
 
906
  if (idx != -1) {
 
907
#if SOQT_DEBUG
 
908
    SoDebugError::postWarning("SoQtRenderArea::registerDevice",
 
909
                              "device already registered");
 
910
#endif // SOQT_DEBUG
 
911
    return;
 
912
  }
 
913
 
 
914
  PRIVATE(this)->devicelist->append(device);
 
915
  QWidget * w = this->getGLWidget();
 
916
  if (w != NULL) {
 
917
#ifdef __COIN_SOXT__
 
918
    device->enable(w, (SoXtEventHandler *) &SoQtGLWidget::eventHandler, (void *)this);
 
919
#else
 
920
    device->enable(w, &SoQtGLWidgetP::eventHandler, (void *)this);
 
921
#endif
 
922
    device->setWindowSize(this->getGLSize());
 
923
  }
 
924
}
 
925
 
 
926
/*!
 
927
  This method removes \a device from the list of devices handling
 
928
  events for this component.
 
929
*/
 
930
void
 
931
SoQtRenderArea::unregisterDevice(SoQtDevice * device)
 
932
{
 
933
  assert(PRIVATE(this)->devicelist != NULL);
 
934
  const int idx = PRIVATE(this)->devicelist->find(device);
 
935
  if (idx == -1) {
 
936
#if SOQT_DEBUG
 
937
    SoDebugError::post("SoQtRenderArea::unregisterDevice",
 
938
                       "tried to remove nonexisting device");
 
939
#endif // SOQT_DEBUG
 
940
    return;
 
941
  }
 
942
 
 
943
  PRIVATE(this)->devicelist->remove(idx);
 
944
  QWidget * w = this->getGLWidget();
 
945
  if (w != NULL) { device->disable(w, NULL, NULL); }
 
946
}
 
947
 
 
948
// *************************************************************************
 
949
 
 
950
// Documented in superclass.
 
951
void
 
952
SoQtRenderArea::afterRealizeHook(void)
 
953
{
 
954
  inherited::afterRealizeHook();
 
955
 
 
956
#ifdef HAVE_JOYSTICK_LINUX
 
957
  if (SoQtLinuxJoystick::exists())
 
958
    this->registerDevice(new SoQtLinuxJoystick);
 
959
#endif // HAVE_JOYSTICK_LINUX
 
960
 
 
961
  if (SoQtSpaceball::exists())
 
962
    this->registerDevice(new SoQtSpaceball);
 
963
}
 
964
 
 
965
/*!
 
966
  This method sets the scene graph to be rendered in the normal bitmap
 
967
  planes.
 
968
 
 
969
  \sa getSceneGraph(), setOverlaySceneGraph()
 
970
*/
 
971
void
 
972
SoQtRenderArea::setSceneGraph(SoNode * scene)
 
973
{
 
974
  PRIVATE(this)->normalManager->setSceneGraph(scene);
 
975
}
 
976
 
 
977
/*!
 
978
  This method returns a reference to the scene graph root node as set
 
979
  by the user.
 
980
 
 
981
  \sa SoQtRenderArea::getSceneManager()
 
982
*/
 
983
SoNode *
 
984
SoQtRenderArea::getSceneGraph(void)
 
985
{
 
986
  return PRIVATE(this)->normalManager->getSceneGraph();
 
987
}
 
988
 
 
989
/*!
 
990
  This method sets the scene graph to render for the overlay bitmap
 
991
  planes.
 
992
 
 
993
  It will automatically take care of setting up overplay planes in the
 
994
  OpenGL canvas if the OpenGL hardware and driver supports it.
 
995
 
 
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.
 
1002
 
 
1003
  \sa setSceneGraph(), getOverlaySceneGraph()
 
1004
*/
 
1005
void
 
1006
SoQtRenderArea::setOverlaySceneGraph(SoNode * scene)
 
1007
{
 
1008
  SoNode * oldroot = this->getOverlaySceneGraph();
 
1009
  PRIVATE(this)->overlayManager->setSceneGraph(scene);
 
1010
 
 
1011
  if (!oldroot && scene) { this->setOverlayRender(TRUE); }
 
1012
  else if (oldroot && !scene) { this->setOverlayRender(FALSE); }
 
1013
}
 
1014
 
 
1015
/*!
 
1016
  This method returns the scene graph for the overlay scene.
 
1017
*/
 
1018
SoNode *
 
1019
SoQtRenderArea::getOverlaySceneGraph(void)
 
1020
{
 
1021
  return PRIVATE(this)->overlayManager->getSceneGraph();
 
1022
}
 
1023
 
 
1024
// *************************************************************************
 
1025
 
 
1026
/*!
 
1027
  This method sets the background color of the scene.
 
1028
*/
 
1029
void
 
1030
SoQtRenderArea::setBackgroundColor(const SbColor & color)
 
1031
{
 
1032
  assert(PRIVATE(this)->normalManager != NULL);
 
1033
  PRIVATE(this)->normalManager->setBackgroundColor(color);
 
1034
  this->scheduleRedraw();
 
1035
}
 
1036
 
 
1037
/*!
 
1038
  This method returns the background color for the scene.
 
1039
*/
 
1040
const SbColor &
 
1041
SoQtRenderArea::getBackgroundColor(void) const
 
1042
{
 
1043
  assert(PRIVATE(this)->normalManager != NULL);
 
1044
  return PRIVATE(this)->normalManager->getBackgroundColor();
 
1045
}
 
1046
 
 
1047
// *************************************************************************
 
1048
 
 
1049
/*!
 
1050
  This method sets the index of the background color for the scene.
 
1051
*/
 
1052
void
 
1053
SoQtRenderArea::setBackgroundIndex(int idx)
 
1054
{
 
1055
  assert(PRIVATE(this)->normalManager != NULL);
 
1056
  PRIVATE(this)->normalManager->setBackgroundIndex(idx);
 
1057
  this->scheduleRedraw();
 
1058
}
 
1059
 
 
1060
/*!
 
1061
  This method returns the index of the background color for the scene.
 
1062
*/
 
1063
int
 
1064
SoQtRenderArea::getBackgroundIndex(void) const
 
1065
{
 
1066
  assert(PRIVATE(this)->normalManager != NULL);
 
1067
  return PRIVATE(this)->normalManager->getBackgroundIndex();
 
1068
}
 
1069
 
 
1070
// *************************************************************************
 
1071
 
 
1072
/*!
 
1073
  This method sets the index of the background for the overlay scene.
 
1074
*/
 
1075
void
 
1076
SoQtRenderArea::setOverlayBackgroundIndex(int idx)
 
1077
{
 
1078
  assert(PRIVATE(this)->overlayManager != NULL);
 
1079
  PRIVATE(this)->overlayManager->setBackgroundIndex(idx);
 
1080
  this->scheduleOverlayRedraw();
 
1081
}
 
1082
 
 
1083
/*!
 
1084
  This method returns the index of the background for the overlay scene.
 
1085
*/
 
1086
int
 
1087
SoQtRenderArea::getOverlayBackgroundIndex(void) const
 
1088
{
 
1089
  assert(PRIVATE(this)->overlayManager != NULL);
 
1090
  return PRIVATE(this)->overlayManager->getBackgroundIndex();
 
1091
}
 
1092
 
 
1093
// *************************************************************************
 
1094
 
 
1095
/*!
 
1096
  This method sets the colormap for the scene.
 
1097
*/
 
1098
void
 
1099
SoQtRenderArea::setColorMap(int start, int num, const SbColor * colors)
 
1100
{
 
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();
 
1108
}
 
1109
 
 
1110
/*!
 
1111
  This method sets the colormap for the overlay scene.
 
1112
*/
 
1113
void
 
1114
SoQtRenderArea::setOverlayColorMap(int start, int num,
 
1115
                                      const SbColor * colors)
 
1116
{
 
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];
 
1123
  }
 
1124
  this->scheduleOverlayRedraw();
 
1125
}
 
1126
 
 
1127
// *************************************************************************
 
1128
 
 
1129
/*!
 
1130
  This method sets the viewport region.
 
1131
*/
 
1132
void
 
1133
SoQtRenderArea::setViewportRegion(const SbViewportRegion & region)
 
1134
{
 
1135
  if (region.getWindowSize()[0] == -1) return;
 
1136
 
 
1137
#if SOQT_DEBUG && 0 // debug
 
1138
  SoDebugError::postInfo("SoQtRenderArea::setViewportRegion",
 
1139
                         "size=<%d, %d>",
 
1140
                         region.getWindowSize()[0],
 
1141
                         region.getWindowSize()[1]);
 
1142
#endif // debug
 
1143
 
 
1144
  PRIVATE(this)->normalManager->setViewportRegion(region);
 
1145
  PRIVATE(this)->overlayManager->setViewportRegion(region);
 
1146
  this->scheduleRedraw();
 
1147
}
 
1148
 
 
1149
/*!
 
1150
  This method returns the viewport region.
 
1151
*/
 
1152
const SbViewportRegion &
 
1153
SoQtRenderArea::getViewportRegion(void) const
 
1154
{
 
1155
  assert(PRIVATE(this)->normalManager != NULL);
 
1156
  return PRIVATE(this)->normalManager->getGLRenderAction()->getViewportRegion();
 
1157
}
 
1158
 
 
1159
// *************************************************************************
 
1160
 
 
1161
/*!
 
1162
  This method sets the transparency type to be used for the scene.
 
1163
*/
 
1164
void
 
1165
SoQtRenderArea::setTransparencyType(SoGLRenderAction::TransparencyType type)
 
1166
{
 
1167
  assert(PRIVATE(this)->normalManager != NULL);
 
1168
  PRIVATE(this)->normalManager->getGLRenderAction()->setTransparencyType(type);
 
1169
  PRIVATE(this)->overlayManager->getGLRenderAction()->setTransparencyType(type);
 
1170
  this->scheduleRedraw();
 
1171
}
 
1172
 
 
1173
/*!
 
1174
  This method returns the transparency type used for the scene.
 
1175
*/
 
1176
SoGLRenderAction::TransparencyType
 
1177
SoQtRenderArea::getTransparencyType(void) const
 
1178
{
 
1179
  assert(PRIVATE(this)->normalManager != NULL);
 
1180
  return PRIVATE(this)->normalManager->getGLRenderAction()->getTransparencyType();
 
1181
}
 
1182
 
 
1183
// *************************************************************************
 
1184
 
 
1185
/*!
 
1186
  This method sets the antialiasing used for the scene.
 
1187
 
 
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
 
1191
  function.
 
1192
 
 
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().
 
1198
*/
 
1199
void
 
1200
SoQtRenderArea::setAntialiasing(SbBool smoothing, int numPasses)
 
1201
{
 
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);
 
1206
 
 
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
 
1214
  // bug.
 
1215
  //
 
1216
  // We should perhaps throw in a configure check for the
 
1217
  // SoSceneManager::setAntialiasing() method and only activate this
 
1218
  // code when actually needed?
 
1219
  //                                                   mortene@sim.no
 
1220
  enum { MGRS = 2 };
 
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();
 
1225
    if (glra) {
 
1226
      glra->setSmoothing(smoothing);
 
1227
      glra->setNumPasses(numPasses);
 
1228
    }
 
1229
  }
 
1230
 
 
1231
  this->scheduleRedraw();
 
1232
}
 
1233
 
 
1234
/*!
 
1235
  This method returns the antialiasing used for the scene.
 
1236
*/
 
1237
void
 
1238
SoQtRenderArea::getAntialiasing(SbBool & smoothing, int & numPasses) const
 
1239
{
 
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.
 
1248
 
 
1249
  assert(PRIVATE(this)->normalManager != NULL);
 
1250
 
 
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();
 
1256
}
 
1257
 
 
1258
/*!
 
1259
  This method sets whether the render buffer should be cleared before
 
1260
  rendering.
 
1261
 
 
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.
 
1265
 
 
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.
 
1269
*/
 
1270
void
 
1271
SoQtRenderArea::setClearBeforeRender(SbBool enable, SbBool zbEnable)
 
1272
{
 
1273
  PRIVATE(this)->clear = enable;
 
1274
  PRIVATE(this)->clearZBuffer = zbEnable;
 
1275
 
 
1276
  this->scheduleRedraw();
 
1277
}
 
1278
 
 
1279
/*!
 
1280
  This method returns whether the render buffer is cleared before each
 
1281
  render.
 
1282
*/
 
1283
SbBool
 
1284
SoQtRenderArea::isClearBeforeRender(void) const
 
1285
{
 
1286
  return PRIVATE(this)->clear;
 
1287
}
 
1288
 
 
1289
/*!
 
1290
  This method returns whether the render buffer's Z buffer is cleared
 
1291
  before each render.
 
1292
*/
 
1293
SbBool
 
1294
SoQtRenderArea::isClearZBufferBeforeRender(void) const
 
1295
{
 
1296
  return PRIVATE(this)->clearZBuffer;
 
1297
}
 
1298
 
 
1299
/*!
 
1300
  This method sets whether the overlay render buffer should be cleared
 
1301
  before each render or not.
 
1302
*/
 
1303
void
 
1304
SoQtRenderArea::setClearBeforeOverlayRender(SbBool enable)
 
1305
{
 
1306
  PRIVATE(this)->clearOverlay = enable;
 
1307
  this->scheduleOverlayRedraw();
 
1308
}
 
1309
 
 
1310
/*!
 
1311
  This method returns whether the overlay render buffer is cleared
 
1312
  before each redraw or not.
 
1313
*/
 
1314
SbBool
 
1315
SoQtRenderArea::isClearBeforeOverlayRender(void) const
 
1316
{
 
1317
  return PRIVATE(this)->clearOverlay;
 
1318
}
 
1319
 
 
1320
/*!
 
1321
  This method sets whether redrawing should be handled automatically
 
1322
  or not when data in the scenegraph changes.
 
1323
 
 
1324
  The default setting causes the renderarea to automatically trigger a
 
1325
  redraw of the scenegraph contents.
 
1326
*/
 
1327
void
 
1328
SoQtRenderArea::setAutoRedraw(SbBool enable)
 
1329
{
 
1330
  if (enable) {
 
1331
    PRIVATE(this)->normalManager->setRenderCallback(SoQtRenderAreaP::renderCB, this);
 
1332
    PRIVATE(this)->overlayManager->setRenderCallback(SoQtRenderAreaP::renderCB, this);
 
1333
  }
 
1334
  else {
 
1335
    PRIVATE(this)->normalManager->setRenderCallback(NULL, NULL);
 
1336
    PRIVATE(this)->overlayManager->setRenderCallback(NULL, NULL);
 
1337
  }
 
1338
 
 
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;
 
1344
}
 
1345
 
 
1346
/*!
 
1347
  This method returns whether redrawing is handled automatically 
 
1348
  not.
 
1349
*/
 
1350
SbBool
 
1351
SoQtRenderArea::isAutoRedraw(void) const
 
1352
{
 
1353
  return PRIVATE(this)->autoRedraw;
 
1354
}
 
1355
 
 
1356
/*!
 
1357
  This method sets the redraw priority.
 
1358
*/
 
1359
void
 
1360
SoQtRenderArea::setRedrawPriority(uint32_t priority)
 
1361
{
 
1362
  PRIVATE(this)->normalManager->setRedrawPriority(priority);
 
1363
  PRIVATE(this)->overlayManager->setRedrawPriority(priority);
 
1364
}
 
1365
 
 
1366
/*!
 
1367
  This method returns the redraw priority.
 
1368
*/
 
1369
uint32_t
 
1370
SoQtRenderArea::getRedrawPriority(void) const
 
1371
{
 
1372
  assert(PRIVATE(this)->normalManager != NULL);
 
1373
  return PRIVATE(this)->normalManager->getRedrawPriority();
 
1374
}
 
1375
 
 
1376
/*!
 
1377
  This function returns the default redraw priority.
 
1378
*/
 
1379
uint32_t
 
1380
SoQtRenderArea::getDefaultRedrawPriority(void)
 
1381
{
 
1382
  return SoSceneManager::getDefaultRedrawPriority();
 
1383
}
 
1384
 
 
1385
/*!
 
1386
  This method causes the immediate rendering of the scene, by calling
 
1387
  SoQtRenderArea::redraw().
 
1388
*/
 
1389
void
 
1390
SoQtRenderArea::render(void)
 
1391
{
 
1392
  this->redraw();
 
1393
}
 
1394
 
 
1395
/*!
 
1396
  This method renders the overlay scene.
 
1397
*/
 
1398
void
 
1399
SoQtRenderArea::renderOverlay(void)
 
1400
{
 
1401
  this->redrawOverlay();
 
1402
}
 
1403
 
 
1404
/*!
 
1405
  This method schedules a redraw to happen at a later time (when the
 
1406
  application has processed it's other events first).
 
1407
*/
 
1408
void
 
1409
SoQtRenderArea::scheduleRedraw(void)
 
1410
{
 
1411
#if SOQT_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug
 
1412
  SoDebugError::postInfo("SoQtRenderArea::scheduleRedraw",
 
1413
                         "invoked");
 
1414
#endif // debug
 
1415
 
 
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.
 
1421
}
 
1422
 
 
1423
/*!
 
1424
  This method schedules a redraw of the overlay scene.
 
1425
*/
 
1426
void
 
1427
SoQtRenderArea::scheduleOverlayRedraw(void)
 
1428
{
 
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.
 
1434
}
 
1435
 
 
1436
#ifndef DOXYGEN_SKIP_THIS
 
1437
void
 
1438
SoQtRenderAreaP::replaceSoSelectionMonitor(SoSelection * newsel,
 
1439
                                              SoSelection * oldsel) const
 
1440
{
 
1441
  if (newsel) { newsel->ref(); }
 
1442
 
 
1443
  if (oldsel) {
 
1444
    oldsel->removeChangeCallback(SoQtRenderAreaP::selection_redraw_cb,
 
1445
                                 PUBLIC(this));
 
1446
    oldsel->unref();
 
1447
  }
 
1448
 
 
1449
  if (newsel) {
 
1450
    newsel->addChangeCallback(SoQtRenderAreaP::selection_redraw_cb,
 
1451
                              PUBLIC(this));
 
1452
  }
 
1453
}
 
1454
#endif // DOXYGEN_SKIP_THIS
 
1455
 
 
1456
// FIXME: the interface below is badly designed, see the comment in
 
1457
// the function documentation. 20001002 mortene.
 
1458
 
 
1459
/*!
 
1460
  Do automatic redraw of the scenegraph when a selection under the
 
1461
  SoSelection node is changed.
 
1462
 
 
1463
  Pass \c NULL to deactivate.
 
1464
 
 
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.)
 
1469
*/
 
1470
void
 
1471
SoQtRenderArea::redrawOnSelectionChange(SoSelection * selection)
 
1472
{
 
1473
  PRIVATE(this)->replaceSoSelectionMonitor(selection, PRIVATE(this)->normalselection);
 
1474
  PRIVATE(this)->normalselection = selection;
 
1475
}
 
1476
 
 
1477
/*!
 
1478
  Do automatic redraw of the scenegraph in the overlay planes when a
 
1479
  selection under the SoSelection node is changed.
 
1480
 
 
1481
  Pass \c NULL to deactivate.
 
1482
 
 
1483
  \sa SoQtRenderArea::redrawOnSelectionChange()
 
1484
*/
 
1485
void
 
1486
SoQtRenderArea::redrawOverlayOnSelectionChange(SoSelection * selection)
 
1487
{
 
1488
  PRIVATE(this)->replaceSoSelectionMonitor(selection, PRIVATE(this)->overlayselection);
 
1489
  PRIVATE(this)->overlayselection = selection;
 
1490
}
 
1491
 
 
1492
/*!
 
1493
  This method sets the render area event callback.
 
1494
*/
 
1495
void
 
1496
SoQtRenderArea::setEventCallback(SoQtRenderAreaEventCB * func,
 
1497
                                    void * user)
 
1498
{
 
1499
  PRIVATE(this)->appeventhandler = func;
 
1500
  PRIVATE(this)->appeventhandlerdata = user;
 
1501
}
 
1502
 
 
1503
/*!
 
1504
  This method sets the normal scene SoSceneManager object.
 
1505
*/
 
1506
void
 
1507
SoQtRenderArea::setSceneManager(SoSceneManager * manager)
 
1508
{
 
1509
  assert(PRIVATE(this)->normalManager != NULL);
 
1510
  PRIVATE(this)->normalManager->setRenderCallback(NULL, NULL);
 
1511
  delete PRIVATE(this)->normalManager;
 
1512
  PRIVATE(this)->normalManager = manager;
 
1513
}
 
1514
 
 
1515
/*!
 
1516
  This method returns the normal scene SoSceneManager object.
 
1517
 
 
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.
 
1526
 
 
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.
 
1531
*/
 
1532
SoSceneManager *
 
1533
SoQtRenderArea::getSceneManager(void) const
 
1534
{
 
1535
  return PRIVATE(this)->normalManager;
 
1536
}
 
1537
 
 
1538
/*!
 
1539
  This method sets the overlay scene SoSceneManager object.
 
1540
*/
 
1541
void
 
1542
SoQtRenderArea::setOverlaySceneManager(SoSceneManager * manager)
 
1543
{
 
1544
  PRIVATE(this)->overlayManager = manager;
 
1545
}
 
1546
 
 
1547
/*!
 
1548
  This method returns the overlay scene SoSceneManager object.
 
1549
*/
 
1550
SoSceneManager *
 
1551
SoQtRenderArea::getOverlaySceneManager(void) const
 
1552
{
 
1553
  return PRIVATE(this)->overlayManager;
 
1554
}
 
1555
 
 
1556
/*!
 
1557
  This method sets the SoGLRenderAction object for the normal scene.
 
1558
*/
 
1559
void
 
1560
SoQtRenderArea::setGLRenderAction(SoGLRenderAction * action)
 
1561
{
 
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());
 
1567
}
 
1568
 
 
1569
/*!
 
1570
  This method returns the SoGLRenderAction object for the normal scene.
 
1571
*/
 
1572
SoGLRenderAction *
 
1573
SoQtRenderArea::getGLRenderAction(void) const
 
1574
{
 
1575
  assert(PRIVATE(this)->normalManager != NULL);
 
1576
  return PRIVATE(this)->normalManager->getGLRenderAction();
 
1577
}
 
1578
 
 
1579
/*!
 
1580
  This method sets the SoGLRenderAction object for rendering the
 
1581
  overlay scenegraph.
 
1582
*/
 
1583
void
 
1584
SoQtRenderArea::setOverlayGLRenderAction(SoGLRenderAction * action)
 
1585
{
 
1586
  assert(PRIVATE(this)->overlayManager != NULL);
 
1587
  PRIVATE(this)->overlayManager->setGLRenderAction(action);
 
1588
}
 
1589
 
 
1590
/*!
 
1591
  This method returns the SoGLRenderAction object for the overlay scene
 
1592
  graph.
 
1593
*/
 
1594
SoGLRenderAction *
 
1595
SoQtRenderArea::getOverlayGLRenderAction(void) const
 
1596
{
 
1597
  assert(PRIVATE(this)->overlayManager != NULL);
 
1598
  return PRIVATE(this)->overlayManager->getGLRenderAction();
 
1599
}
 
1600
 
 
1601
/*!
 
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
 
1606
  doublebuffer mode).
 
1607
 
 
1608
  After setting up the OpenGL context, it calls actualRedraw() for the
 
1609
  actual scenegraph rendering to take place.
 
1610
 
 
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.
 
1614
 
 
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.
 
1619
*/
 
1620
void
 
1621
SoQtRenderArea::redraw(void)
 
1622
{
 
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");
 
1628
#endif // debug
 
1629
 
 
1630
  if (! this->isVisible() || !this->hasNormalGLArea() || this->waitForExpose)
 
1631
    return;
 
1632
  this->glLockNormal(); // this makes the GL context "current"
 
1633
 
 
1634
  SbBool drawfront =
 
1635
    ! this->isDoubleBuffer() ||
 
1636
    this->isDrawToFrontBufferEnable();
 
1637
 
 
1638
  glDrawBuffer(drawfront ? GL_FRONT : GL_BACK);
 
1639
 
 
1640
  this->actualRedraw();
 
1641
 
 
1642
  if (!drawfront) { this->glSwapBuffers(); }
 
1643
  else { this->glFlushBuffer(); }
 
1644
  this->glUnlockNormal();
 
1645
 
 
1646
#if SOQT_DEBUG && RENDERAREA_DEBUG_REDRAWS // debug
 
1647
  SoDebugError::postInfo("SoQtRenderArea::render", "done");
 
1648
#endif // debug
 
1649
}
 
1650
 
 
1651
// Note: the following function documentation block will also be used
 
1652
// for all the miscellaneous viewer subclasses, so keep it general.
 
1653
/*!
 
1654
  This method instantly redraws the normal (non-overlay) scenegraph by
 
1655
  calling SoSceneManager::render().
 
1656
 
 
1657
  Subclasses may override this method to add their own rendering
 
1658
  before or after Coin renders it's scenegraph.
 
1659
 
 
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:
 
1663
 
 
1664
  \code
 
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.
 
1668
  
 
1669
  // *************************************************************************
 
1670
  
 
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>
 
1682
  
 
1683
  #include <GL/gl.h>
 
1684
  
 
1685
  // *************************************************************************
 
1686
  
 
1687
  class MyExaminerViewer : public SoQtExaminerViewer {
 
1688
  
 
1689
  public:
 
1690
    MyExaminerViewer(QWidget * parent, const char * filename);
 
1691
    ~MyExaminerViewer();
 
1692
  
 
1693
  protected:
 
1694
    virtual void actualRedraw(void);
 
1695
  
 
1696
  private:
 
1697
    SoSeparator * bckgroundroot;
 
1698
    SoSeparator * foregroundroot;
 
1699
    SoRotationXYZ * arrowrotation;
 
1700
  };
 
1701
  
 
1702
  MyExaminerViewer::MyExaminerViewer(QWidget * parent, const char * filename)
 
1703
    : SoQtExaminerViewer(parent)
 
1704
  {
 
1705
    // Coin should not clear the pixel-buffer, so the background image
 
1706
    // is not removed.
 
1707
    this->setClearBeforeRender(FALSE, TRUE);
 
1708
  
 
1709
  
 
1710
    // Set up background scenegraph with image in it.
 
1711
  
 
1712
    this->bckgroundroot = new SoSeparator;
 
1713
    this->bckgroundroot->ref();
 
1714
  
 
1715
    SoOrthographicCamera * cam = new SoOrthographicCamera;
 
1716
    cam->position = SbVec3f(0, 0, 1);
 
1717
    cam->height = 1;
 
1718
    // SoImage will be at z==0.0.
 
1719
    cam->nearDistance = 0.5;
 
1720
    cam->farDistance = 1.5;
 
1721
  
 
1722
    SoImage * img = new SoImage;
 
1723
    img->vertAlignment = SoImage::HALF;
 
1724
    img->horAlignment = SoImage::CENTER;
 
1725
    img->filename = filename;
 
1726
  
 
1727
    this->bckgroundroot->addChild(cam);
 
1728
    this->bckgroundroot->addChild(img);
 
1729
  
 
1730
    // Set up foreground, overlayed scenegraph.
 
1731
  
 
1732
    this->foregroundroot = new SoSeparator;
 
1733
    this->foregroundroot->ref();
 
1734
  
 
1735
    SoLightModel * lm = new SoLightModel;
 
1736
    lm->model = SoLightModel::BASE_COLOR;
 
1737
  
 
1738
    SoBaseColor * bc = new SoBaseColor;
 
1739
    bc->rgb = SbColor(1, 1, 0);
 
1740
  
 
1741
    cam = new SoOrthographicCamera;
 
1742
    cam->position = SbVec3f(0, 0, 5);
 
1743
    cam->height = 10;
 
1744
    cam->nearDistance = 0;
 
1745
    cam->farDistance = 10;
 
1746
  
 
1747
    const double ARROWSIZE = 2.0;
 
1748
  
 
1749
    SoTranslation * posit = new SoTranslation;
 
1750
    posit->translation = SbVec3f(-2.5 * ARROWSIZE, 1.5 * ARROWSIZE, 0);
 
1751
  
 
1752
    arrowrotation = new SoRotationXYZ;
 
1753
    arrowrotation->axis = SoRotationXYZ::Z;
 
1754
  
 
1755
    SoTranslation * offset = new SoTranslation;
 
1756
    offset->translation = SbVec3f(ARROWSIZE/2.0, 0, 0);
 
1757
  
 
1758
    SoCube * cube = new SoCube;
 
1759
    cube->width = ARROWSIZE;
 
1760
    cube->height = ARROWSIZE/15.0;
 
1761
  
 
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);
 
1769
  }
 
1770
  
 
1771
  MyExaminerViewer::~MyExaminerViewer()
 
1772
  {
 
1773
    this->bckgroundroot->unref();
 
1774
    this->foregroundroot->unref();
 
1775
  }
 
1776
  
 
1777
  void
 
1778
  MyExaminerViewer::actualRedraw(void)
 
1779
  {
 
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
 
1783
    // the action..
 
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]);
 
1788
  
 
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);
 
1792
  
 
1793
    // Render our scenegraph with the image.
 
1794
    SoGLRenderAction * glra = this->getGLRenderAction();
 
1795
    glra->apply(this->bckgroundroot);
 
1796
  
 
1797
  
 
1798
    // Render normal scenegraph.
 
1799
    SoQtExaminerViewer::actualRedraw();
 
1800
  
 
1801
  
 
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);
 
1807
  }
 
1808
  
 
1809
  // *************************************************************************
 
1810
  
 
1811
  int
 
1812
  main(int argc, char ** argv)
 
1813
  {
 
1814
    if (argc != 2) {
 
1815
      (void)fprintf(stderr, "\n\n\tUsage: %s <image-filename>\n\n", argv[0]);
 
1816
      exit(1);
 
1817
    }
 
1818
  
 
1819
    QWidget * window = SoQt::init(argv[0]);
 
1820
  
 
1821
    MyExaminerViewer * viewer = new MyExaminerViewer(window, argv[1]);
 
1822
  
 
1823
    viewer->setSceneGraph(new SoCone);
 
1824
    viewer->show();
 
1825
  
 
1826
    SoQt::show(window);
 
1827
    SoQt::mainLoop();
 
1828
  
 
1829
    delete viewer;
 
1830
    return 0;
 
1831
  }
 
1832
  
 
1833
  // *************************************************************************
 
1834
  \endcode
 
1835
*/
 
1836
void
 
1837
SoQtRenderArea::actualRedraw(void)
 
1838
{
 
1839
  assert(PRIVATE(this)->normalManager != NULL);
 
1840
  if ( !this->isVisible() ) return;
 
1841
  PRIVATE(this)->normalManager->render(PRIVATE(this)->clear, PRIVATE(this)->clearZBuffer);
 
1842
}
 
1843
 
 
1844
/*!
 
1845
  This method redraws the overlay scene.
 
1846
*/
 
1847
void
 
1848
SoQtRenderArea::redrawOverlay(void)
 
1849
{
 
1850
  if (!this->isVisible() || this->waitForExpose || !this->hasOverlayGLArea()) {
 
1851
    return;
 
1852
  }
 
1853
  
 
1854
  this->glLockOverlay();
 
1855
  this->actualOverlayRedraw();
 
1856
  this->glFlushBuffer();
 
1857
  this->glUnlockOverlay();
 
1858
}
 
1859
 
 
1860
/*!
 
1861
  This method renders the overlay scene.
 
1862
*/
 
1863
void
 
1864
SoQtRenderArea::actualOverlayRedraw(void)
 
1865
{
 
1866
  assert(PRIVATE(this)->overlayManager != NULL);
 
1867
  if (! this->isVisible()) return;
 
1868
  PRIVATE(this)->overlayManager->render(PRIVATE(this)->clearOverlay,
 
1869
                                        PRIVATE(this)->clearZBuffer);
 
1870
}
 
1871
 
 
1872
/*!
 
1873
  This method is invoked to initialize the normal graphics.
 
1874
*/
 
1875
void
 
1876
SoQtRenderArea::initGraphic(void)
 
1877
{
 
1878
  SoSceneManager * mgr = this->getSceneManager();
 
1879
  if (mgr) {
 
1880
    mgr->reinitialize();
 
1881
    mgr->setRGBMode(this->isRGBMode());
 
1882
 
 
1883
    SoGLRenderAction * renderaction = mgr->getGLRenderAction();
 
1884
    renderaction->setCacheContext(SoAny::si()->getSharedCacheContextId(this));
 
1885
    SbBool isdirect = SoGuiGLWidgetP::isDirectRendering(this);
 
1886
    renderaction->setRenderingIsRemote(!isdirect);
 
1887
  }
 
1888
  // FIXME: if not RGB mode, load colormap. pederb.
 
1889
 
 
1890
  inherited::initGraphic();
 
1891
}
 
1892
 
 
1893
/*!
 
1894
  This method is invoked to initialize the overlay graphics.
 
1895
*/
 
1896
void
 
1897
SoQtRenderArea::initOverlayGraphic(void)
 
1898
{
 
1899
  SoSceneManager * mgr = this->getOverlaySceneManager();
 
1900
  if (mgr) {
 
1901
    mgr->reinitialize();
 
1902
    // FIXME: does overlays really _have_ to be in colorindex mode?
 
1903
    // 20020916 mortene.
 
1904
    mgr->setRGBMode(FALSE);
 
1905
 
 
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.
 
1911
  }
 
1912
  // FIXME: if not RGB mode, load colormap. pederb.
 
1913
 
 
1914
  // FIXME: shouldn't we do inherited::initOverlayGraphic() ? 20010831 mortene.
 
1915
}
 
1916
 
 
1917
// doc in super
 
1918
void
 
1919
SoQtRenderArea::sizeChanged(const SbVec2s & size)
 
1920
{
 
1921
#if SOQT_DEBUG && 0
 
1922
  SoDebugError::postInfo("SoQtRenderArea::sizeChanged",
 
1923
                          "invoked, <%d, %d>", size[0], size[1]);
 
1924
#endif // SOQT_DEBUG
 
1925
 
 
1926
  SbVec2s newsize(size);
 
1927
 
 
1928
  if (size[0] == -1)
 
1929
    return;
 
1930
 
 
1931
  assert(PRIVATE(this)->normalManager != NULL);
 
1932
  assert(PRIVATE(this)->overlayManager != NULL);
 
1933
 
 
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):
 
1936
  // 
 
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
 
1940
  // window blank...
 
1941
 
 
1942
#if defined Q_WS_MAC && ((QT_VERSION == 0x030100) || (QT_VERSION == 0x030101))
 
1943
 
 
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)) {
 
1948
 
 
1949
    if (this->getTypeId() == SoQtRenderArea::getClassTypeId()) { 
 
1950
      // SoQtRenderArea used as standalone component
 
1951
      newsize -= SbVec2s(0, 15);
 
1952
 
 
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");
 
1966
      } 
 
1967
    } 
 
1968
  }
 
1969
 
 
1970
#endif
 
1971
 
 
1972
  this->setGLSize(newsize);
 
1973
  const SbVec2s glsize = this->getGLSize();
 
1974
 
 
1975
 
 
1976
#if SOQT_DEBUG && 0
 
1977
  SoDebugError::postInfo("SoQtRenderArea::sizeChanged",
 
1978
                          "glsize==<%d, %d>", glsize[0], glsize[1]);
 
1979
#endif // SOQT_DEBUG
 
1980
 
 
1981
  if (glsize[0] <= 0 || glsize[1] <= 0)
 
1982
    return;
 
1983
 
 
1984
  this->setViewportRegion(SbViewportRegion(glsize));
 
1985
  PRIVATE(this)->setDevicesWindowSize(glsize);
 
1986
 
 
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);
 
1991
 
 
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);
 
1996
 
 
1997
  inherited::sizeChanged(glsize);
 
1998
 
 
1999
  // this->scheduleRedraw(); // already done through setViewportRegion()
 
2000
}
 
2001
 
 
2002
// Documented in superclass.
 
2003
void
 
2004
SoQtRenderArea::widgetChanged(QWidget * widget)
 
2005
{
 
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.
 
2010
#if 0
 
2011
  PRIVATE(this)->normalManager->setRGBMode(this->isRGBMode());
 
2012
  PRIVATE(this)->overlayManager->setRGBMode(this->isRGBMode());
 
2013
#endif
 
2014
 
 
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.
 
2018
}
 
2019
 
 
2020
// Documented in superclass.
 
2021
QWidget *
 
2022
SoQtRenderArea::buildWidget(QWidget * parent)
 
2023
{
 
2024
  QWidget * widget = inherited::buildWidget(parent);
 
2025
 
 
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,
 
2033
                     (void *) this);
 
2034
#else
 
2035
      device->enable(this->getGLWidget(),
 
2036
                     &SoQtGLWidgetP::eventHandler, (void *) this);
 
2037
#endif
 
2038
    }
 
2039
  }
 
2040
 
 
2041
  return widget;
 
2042
}
 
2043
 
 
2044
// Documented in superclass.
 
2045
const char *
 
2046
SoQtRenderArea::getDefaultWidgetName(void) const
 
2047
{
 
2048
  static const char defaultWidgetName[] = "SoQtWidgetName";
 
2049
  return defaultWidgetName;
 
2050
}
 
2051
 
 
2052
// Documented in superclass.
 
2053
const char *
 
2054
SoQtRenderArea::getDefaultTitle(void) const
 
2055
{
 
2056
  static const char defaultTitle[] = "Qt RenderArea";
 
2057
  return defaultTitle;
 
2058
}
 
2059
 
 
2060
// Documented in superclass.
 
2061
const char *
 
2062
SoQtRenderArea::getDefaultIconTitle(void) const
 
2063
{
 
2064
  static const char defaultIconTitle[] = "Qt RenderArea";
 
2065
  return defaultIconTitle;
 
2066
}
 
2067
 
 
2068
// *************************************************************************
 
2069
 
 
2070
/*!
 
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.
 
2074
 
 
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
 
2077
  instance.
 
2078
 
 
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.
 
2083
 
 
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.
 
2087
*/
 
2088
SbBool
 
2089
SoQtRenderArea::processSoEvent(const SoEvent * const event)
 
2090
{
 
2091
  if (PRIVATE(this)->overlayManager->processEvent(event)) { return TRUE; }
 
2092
  if (PRIVATE(this)->normalManager->processEvent(event)) { return TRUE; }
 
2093
  return FALSE;
 
2094
}
 
2095
 
 
2096
// *************************************************************************
 
2097
 
 
2098
/*!
 
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().
 
2102
 */
 
2103
void
 
2104
SoQtRenderArea::processEvent(QEvent * event)
 
2105
{
 
2106
  if (PRIVATE(this)->invokeAppCB(event)) { return; }
 
2107
 
 
2108
  const SoEvent * soevent = PRIVATE(this)->getSoEvent(event);
 
2109
 
 
2110
  if (soevent != NULL) {
 
2111
#if SOQT_DEBUG
 
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.
 
2115
    //
 
2116
    // See code comments behind "case" statements below for which
 
2117
    // sequences are available so far.
 
2118
 
 
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:
 
2125
          break;
 
2126
        case SoQtRenderAreaP::OPENGL:  // "glinfo"
 
2127
          this->glLockNormal();
 
2128
          PRIVATE(this)->showOpenGLDriverInformation();
 
2129
          this->glUnlockNormal();
 
2130
          break;
 
2131
        case SoQtRenderAreaP::INVENTOR:  // "ivinfo"
 
2132
          PRIVATE(this)->showInventorInformation();
 
2133
          break;
 
2134
        case SoQtRenderAreaP::TOOLKIT:  // "soinfo"
 
2135
          PRIVATE(this)->showToolkitInformation();
 
2136
          break;
 
2137
        case SoQtRenderAreaP::DUMPSCENEGRAPH:  // "dumpiv"
 
2138
          PRIVATE(this)->dumpScenegraph();
 
2139
          break;
 
2140
        case SoQtRenderAreaP::DUMPCAMERAS:  // "cameras"
 
2141
          PRIVATE(this)->dumpCameras();
 
2142
          break;
 
2143
        case SoQtRenderAreaP::OFFSCREENGRAB:  // "osgrab"
 
2144
          PRIVATE(this)->offScreenGrab();
 
2145
          break;
 
2146
        default:
 
2147
          assert(FALSE && "unknown debug key sequence");
 
2148
          break;
 
2149
        }
 
2150
      }
 
2151
    }
 
2152
#endif // SOQT_DEBUG
 
2153
 
 
2154
    SbBool processed = this->processSoEvent(soevent);
 
2155
    if (processed) return;
 
2156
  }
 
2157
 
 
2158
  inherited::processEvent(event);
 
2159
}
 
2160
 
 
2161
// *************************************************************************
 
2162
 
 
2163
// doc from parent
 
2164
SbBool 
 
2165
SoQtRenderArea::glScheduleRedraw(void)
 
2166
{
 
2167
  this->scheduleRedraw();
 
2168
  if (this->hasOverlayGLArea() && this->getOverlaySceneGraph()) {
 
2169
    this->scheduleOverlayRedraw();
 
2170
  }
 
2171
  return TRUE;
 
2172
}
 
2173
 
 
2174
// *************************************************************************
 
2175
 
 
2176
/*!
 
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.
 
2180
*/
 
2181
SbBool
 
2182
SoQtRenderArea::sendSoEvent(const SoEvent * event)
 
2183
{
 
2184
  return this->processSoEvent(event);
 
2185
}
 
2186
 
 
2187
// *************************************************************************
 
2188
 
 
2189
#undef PRIVATE
 
2190
#undef PUBLIC
 
2191