Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
Microsoft Windows

Introduction

Background:

Open Inventor consists of a portable core component and various window system-specific components:

  • SoXt – X Windows/Motif, see X Windows.
  • SoWin – Microsoft Windows, see this chapter.
  • SoQt – Qt, see Qt. This chapter describes the Open Inventor window system-specific components for the Win32 environment, specifically the SoWin classes.

Architecture:

Open Inventor was designed to be portable and window system independent. It uses a strategy similar to the one used in OpenGL (which Open Inventor uses as its rendering engine). OpenGL is divided into a large core of system-independent functions and a small set of window (and operating system) specific functions. The system-specific functions generally have similar functionality but different parameters. These OpenGL functions are identified by a unique prefix, for example:

System OpenGL prefix
Unix/Linux X11 glX
Win32 (Windows) wgl
OS/2 pgl
Macintosh agl

This has been a successful strategy. Some modification of the program for each platform is necessary, but in most cases the window system-specific calls are used in a small number of places. Of course there may be many other window system and user interface changes that must be made to the program, for example converting a Motif interface into the equivalent Win32 or MFC interface. These changes are independent of the graphics library.

The corresponding prefixes for Open Inventor are:

System Open Inventor prefix
Unix/Linux X11 SoXt
Win32 (Windows) SoWin

The correspondence between Open Inventor components in the Win32 environment and in the Unix environment is illustrated in Open Inventor for Win32 and Unix .

Open Inventor for Win32 and Unix

in The Inventor Mentor (see Open Inventor Component Library) and The Inventor Toolmaker. SoWin is fully decribed in the following section.

There is a very close correspondence between the Unix SoXt classes and the Win32 SoWin classes. This allowed us to define a set of SoXt “aliases” for the SoWin classes that facilitate porting Open Inventor programs from the Unix X11 environment. Using the SoXt aliases, simple Open Inventor programs can often be ported to the Win32 environment with only minor changes. The SoXt aliases are described in their own section.

A significant difference between the Win32 C++ environment and Unix is that much of the new C++ development under Win32 is being done using the Microsoft Foundation Classes (MFC) and the MFC AppWizard. MFC is both a class library that “wraps” the Win32 API and a powerful application framework based on the document/view paradigm. MFC provides a standard implementation of services common to many applications, such as printing, tool bars, and status bars. The MFC AppWizard is a tool that generates a skeleton MFC application that is ready to compile, link, and execute. The AppWizard can automatically add support for various features such as OLE, ODBC (database access), and so on.

So there are actually three parts to the implementation of the window system-specific components of Open Inventor for Win32:

Open Inventor prefix Feature
SoWin Win32-specific classes
SoXt Aliases for SoWin classes

Why two parts instead of just integrating Open Inventor into MFC? In short, because it provides the “best of both worlds.” The way MFC allows direct access to the Win32 API, the Open Inventor component methods are accessible to applications that need them. At the same time, the one-to-one correspondence between SoWin and SoXt classes allows Open Inventor programmers to carry over knowledge from one environment to the other and makes resources such as Open Inventor Mentor Core directly applicable to the Win32 environment. The SoWin classes provide critical flexibility in two areas that will allow Open Inventor to be more quickly adopted and have lasting value in this environment. First, the SoWin classes can be used to build extension classes for application frameworks other than MFC. Second, the SoWin classes can be used to add 3D graphics functionality to existing applications, even in situations where development policy does not allow the class inheritance tree to be modified.

SoXt Alias Classes

Here is a simple Open Inventor program Hello Cone Using the Examiner Viewer. The only difference between this program and the Unix/X11 version shown in The Inventor Mentor is the addition of one line (highlighted below). This header file uses the standard preprocessor symbol “WIN32,” which is defined in the Win32 environment, to change the name of function “main”. Most Win32 programs (the exception is console applications) do not have a function named main. Instead the first entry point in the program is named “WinMain” and has a very different set of parameters. Applications using Open Inventor for Win32 are not required to have a WinMain because the optional SoWin utility library provides one. Open Inventor’s WinMain function performs some basic bookkeeping operations and then calls the application’s “ivMain” function with the same parameters as the familiar Unix “main” function. SoWinApp.h also contains pragma statements to include the current version of INVUxxx.LIB or INVUxxxD.LIB. The code in this header file is under an #ifdef WIN32 for cross-platform portability.

Example : Hello Cone using the SoXt alias classes

C++ :

#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/SoWinApp.h>
int
main( int, char** argv )
{
Widget myWindow = SoXt::init( argv[0] );
if ( myWindow == NULL )
exit( 1 );
SoSeparator* root = new SoSeparator;
root->ref();
SoMaterial* myMaterial = new SoMaterial;
myMaterial->diffuseColor.setValue( 1.0, 0.0, 0.0 );
root->addChild( myMaterial );
root->addChild( new SoCone );
SoXtExaminerViewer* myViewer = new SoXtExaminerViewer( myWindow );
myViewer->setSceneGraph( root );
myViewer->setTitle( "Examiner Viewer" );
myViewer->show();
SoXt::show( myWindow );
SoXt::mainLoop();
return 0;
}

Prior to Open Inventor 5.0, it was necessary to explicitly #define main to ivMain and also to explicitly add
INVUxxx.LIB or INVUxxxD.LIB to the link string. If you include SoWinApp.h in your Win32 (not console) application, you do
not need to put the definition of ivMain directly in your code, and the
correct version of the INVU libraries will be used automatically.

Because the WIN32 symbol is not defined on Unix systems, this program is completely portable. It can be compiled, linked, and executed with no additional changes in either a Win32 or a Unix environment. With one or two exceptions, all the example programs from The Inventor Mentor and The Inventor Toolmaker were made portable with only minor changes similar to the ones shown above. This is highly desirable because these programs are, for the most part, intended to illustrate system-independent features of Open Inventor. Using the SoXt alias classes, the important information in the programs is not obscured by platform differences.

The SoXt alias classes are valuable for more than just simple example programs. Potentially any Open Inventor program that does not make explicit calls to Xlib, Xt, or Motif functions can be ported to Win32 with its SoXt calls intact. For example, the Open Inventor demo program “slotcar” (included with the Open Inventor for Win32 SDK) is a moderately complex program that was ported using the SoXt aliases. Even when there is Motif code to be converted, knowing that SoXt calls map directly to SoWin calls (and generally have the same behavior) means that the SoXt calls could be left in the code, which would reduce the number of “::ifdefs” in the final code. We do not recommend this approach for production code but it can make porting easier for some projects.

Strictly speaking, there are no SoXt classes or data types in Open Inventor for Win32. However, all the SoXt header files are provided. These header files redefine the SoXt classes as the corresponding SoWin classes and the necessary X11 (and Xt and Motif) data types as the corresponding Win32 data types. So, for example, class SoXtExaminerViewer is redefined as class SoWinExaminerViewer . There is an SoWin class that corresponds to each of the SoXt classes. The Win32 SoXt (SoWin ) methods generally perform the same, or very similar, actions as their Unix counterparts.

In order to redefine the X11 data types, we take advantage of the general similarity between the X Window System and the Microsoft Windows System. Both refer to windows using opaque handles, both provide a window hierarchy in which child windows are clipped against their parent window, and so on. The X11 type Window corresponds well to the Win32 type HWND (which is the mapping Open Inventor uses). Win32 does not have a concept directly analogous to the Xt “widget.” However, in Xt there is always exactly one window that corresponds to a particular widget, so Open Inventor for Win32 also maps the Xt type Widget to the Win32 type HWND. Thus the SoXt::init method returns a “Widget” which is actually a window handle which can then be passed to the SoXtExaminerViewer constructor as its parent window.

The SoXt::show method has the same effect
as its Unix equivalent in this situation. It uses the Win32 function ShowWindow to make the application’s top level window visible. The SoXt::mainLoop method also has essentially the same behavior as its
Unix equivalent. It uses the SoXt::nextEvent and SoXt::dispatchEvent methods, which are in turn implemented using
(mostly) the Win32 GetMessage and **
DispatchMessage** functions. More details are given in the SoWin section. The Win32 MSG data type is roughly equivalent
to the X11 Xevent data type. Most of the same basic user interface events
exist in both window systems, for example keypress, mouse button, and mouse motion
events.

SoWin Classes

Here is a simple Open Inventor program Hello Cone Using the Examiner Viewer. This is the same program used as an example in the “ SoXt Aliases ” section. In this example, a minimal translation of the program from Unix to Windows has been done (“**SoXt** ” changed to “ SoWin ” and so on), but the program still has the structure of a Unix/X11 program. If this program was being ported from Unix to Win32, it would be easier (and work just as well) to use the SoXt alias classes described in the previous section. The SoWin version is shown here to illustrate the one-to-one relationship with the SoXt classes.

This version of the program works essentially the same as it would under Unix. Calling SoWin::init with a string creates a top level window for the application and returns (in this case) its window handle. The viewer’s window is created as a child of the top level window. The “show” calls make the various windows visible and SoWin::mainLoop provides the application’s event loop (message loop in Win32 terminology).

Example : Hello Cone using the SoWin classes without Win32

C++ :

#include <Inventor/Win/SoWin.h>
#include <Inventor/Win/viewers/SoWinExaminerViewer.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoSeparator.h>
#ifdef WIN32
#define main ivMain
#endif
int
main( int, char** argv )
{
HWND myWindow = SoWin::init( argv[0] );
if ( myWindow == NULL )
exit( 1 );
SoSeparator* root = new SoSeparator;
root->ref();
SoMaterial* myMaterial = new SoMaterial;
myMaterial->diffuseColor.setValue( 1.0, 0.0, 0.0 );
root->addChild( myMaterial );
root->addChild( new SoCone );
SoWinExaminerViewer* myViewer = new SoWinExaminerViewer( myWindow );
myViewer->setSceneGraph( root );
myViewer->setTitle( "Examiner Viewer" );
myViewer->show();
SoWin::show(myWindow;
SoWin::mainLoop();
return 0;
}

Below is the same simple program again, but written as a native Win32 program. Notice that the code using core Open Inventor classes does not change. These classes are, with a few minor exceptions (see the section called “General Issues”), system independent. Notice that there are minor changes to the code using SoWin classes. Instead of a string, SoWin::init is called with the window handle of the application’s top level window (this window is created by the application in the WinMain function). The SoWin::show and SoWin::mainLoop calls are not used because the application controls the visibility of the top level window and has its own message processing (event) loop.

Also notice that SoWin::isInventorMessage is called at the top of the application’s WndProc. This method was added to Open Inventor specifically for the Win32 environment. Conceptually similar to the Win32 IsDialogMessage function for modeless dialog boxes, it allows Open Inventor to handle certain messages that are only sent to the application’s top level window. For example, when the video mode is 8-bit (256 colors), SoWin automatically creates and manages the palette (color map) that OpenGL needs for rendering. Unlike X11, a Win32 application is responsible for realizing (installing) its own palette when it receives the input focus. Win32 sends the application a special “palette changed” message, but palette change messages are only sent to the application’s top level window, not to the actual drawing window.

Example : Hello Cone using the SoWin classes with Win32

C++ :

#include <windows.h>
#include <Inventor/Win/SoWin.h>
#include <Inventor/Win/viewers/SoWinExaminerViewer.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoSeparator.h>
LRESULT InitInventor( HWND );
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
** ///////////////////////////////////////////////////////////////////////
int WINAPI
WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow )
{
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndclass.hbrBackground = NULL; // Inventor will take care of it
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "Inventor Win32";
RegisterClass( &wndclass );
HWND hwnd =
CreateWindow( "Inventor Win32", "Inventor Win32", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 400, NULL, NULL, hInstance, NULL );
InitInventor( hwnd );
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam;
}
** ///////////////////////////////////////////////////////////////////////
LRESULT
InitInventor( HWND mainWindow )
{
SoWin::init( mainWindow );
SoSeparator* root = new SoSeparator;
root->ref();
SoMaterial* myMaterial = new SoMaterial;
myMaterial->diffuseColor.setValue( 1.0, 0.0, 0.0 );
root->addChild( myMaterial );
root->addChild( new SoCone );
SoWinExaminerViewer* myViewer = new SoWinExaminerViewer( mainWindow );
myViewer->setSceneGraph( root );
myViewer->setTitle( "Examiner Viewer" );
myViewer->show();
return 0;
}
** ///////////////////////////////////////////////////////////////////////
LRESULT CALLBACK
WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
if ( SoWin::isInventorMessage( hwnd, message, wParam, lParam ) )
return TRUE;
switch ( message )
{
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hwnd, message, wParam, lParam );
}

SoWin

The SoWin class initializes Inventor for use with the Win32 window system. All its methods are static convenience functions. Every SoWin class includes all the methods of its corresponding Unix class. Generally these methods have the same, or very similar, behavior. In a few cases the data types have been changed for the Win32 environment. In particular:

  • Type HWND is used in place of the X11 type Window and the Xt type Widget.
  • Type MSG is used in place of the X11 type XEvent. Some of the SoXt methods have no meaning in the Win32 environment. They are retained for convenience, but do nothing. These include getAppContext(), getDisplay(), encodeString(), decodeString(), and getPopupArgs().

Some additional methods specific to the Win32 environment have been added. The isInventorMessage function should be called at the top of the application’s WndProc to ensure that Open Inventor receives messages that Win32 only sends to the application’s top level window. (The need for this function in color palette handling is discussed at the beginning of this section.) The doIdleTasks function processes any pending Open Inventor idle sensors (see SoIdleSensor). By default, idle sensors will be processed even without using this function. However if the Open Inventor delay queue time-out is disabled (using SoDB::setDelaySensorTimeout), the application may need to call doIdleTasks periodically. Note that if the application is using SoWin::mainLoop or SoWin::nextEvent, doIdleTasks is called automatically when the message queue is empty.

SoWinClipboard

The SoWinClipboard class provides copy and paste for Open Inventor data using the Win32 clipboard. It is somewhat less important in the Win32 environment because interfacing to the clipboard is not as complicated as it is under X11. However it is still convenient. The default value of the format parameter in the constructor is the Win32 constant “CF_TEXT”. This is the most common Win32 clipboard format and causes Open Inventor to write data to the clipboard in ASCII format. From the clipboard, CF_TEXT data can be pasted into an Open Inventor application or any text-based application. For example it is often convenient to paste a portion of the scene graph into the Notepad utility to verify its contents.

SoWinComponent

SoWinComponent is the abstract base class for all Open Inventor components. Some of the methods have no meaning in the Win32 environment, including getDisplay(), setIconTitle(), and getIconTitle(). New member variables helpFileName and helpContextId are provided to allow applications to override the default help topic displayed by a component. Editor components, such as SoWinMaterialEditor, have a help item in their menu bar. Viewer components, such as SoWinExaminerViewer, have a help button in their toolbar.

SoWinGLWidget

SoWinGLWidget is the generic component for OpenGL rendering. In addition to the data type mapping discussed in the SoWin topic, there are the following changes:

  • Type HGLRC is used in place of the X11 type GLXContext.
  • Type PIXELFORMATDESCRIPTOR is used in place of the X11 type XVisualInfo. Some behaviors specific to the Win32 environment have been added (usually to preserve a useful feature of the Open Inventor user interface). SoWinGLWidget provides the equivalent of X11’s automatic pointer grab on a mouse button press (using SetCapture()). This ensures that the application will always get the mouse “button up” event corresponding to a “button down” event. This is not normally guaranteed in the Win32 environment. SoWinGLWidget also (optionally) provides the equivalent of X11’s “focus follows pointer” policy. This ensures that Open Inventor viewer components receive the input focus when the cursor enters their window. Because this behavior is not always desirable, it can be disabled using a Win32-specific method (see next section).

Some additional methods specific to the Win32 environment have been added.
The getNormalDC and getOverlayDC functions return the current Win32 Device Context (needed for
wglMakeCurrent). The setStealFocus function enables or
disables emulation of the X11 “focus follows pointer” policy (by default the Open Inventor
viewer components enable this behavior).

Look and Feel

Open Inventor for Win32 has been adapted to the Win32 user interface guidelines, but at the same time preserves the system-independent “look and feel” of the viewer and editor components. Notice that the distinctive Open Inventor thumb wheel interface is preserved and the viewer toolbar uses the same button bitmaps as on other platforms:

"Important"

With the Examiner Viewer, it is possible to define the keys and/or mouse presses associated with the various viewer functions, such as pan, dolly, zoom, etc.

A class derived from SoViewingFunction is defined for each possible viewing function, and must be used for making the association between a key press or mouse press and a viewing function.

"Important"

The following example (which can be found in the directory $OIVHOME/src/Inventor/examples/Features/SetKeyBinding) defines the key and mouse bindings as follows:

  • The F3 through F9 keys toggle between picking mode and a particular viewing function, as follows:
  • F3 key: dolly
  • F4 key: pan
  • F5 key: constrained x-axis rotation
  • F6 key: constrained y-axis rotation
  • F7 key: constrained z-axis rotation
  • F9 key: spherical rotation (as with a standard Examiner Viewer)
  • CTRL + SHIFT + left mouse button (button 1): dolly
  • SHIFT + left mouse button (button 1): pan

Example : Defines key and mouse button bindings for an Examiner Viewer

C++ :

// SoWinExaminerViewerSetKeyBinding class derives from SoWinExaminerViewer
// and defines new key/mouse bindings within its constructor;
SoWinExaminerViewerSetKeyBinding::SoWinExaminerViewerSetKeyBinding( Widget parent,
const char* name,
SbBool buildInsideParent,
SoWinFullViewer::BuildFlag flag,
SoWinViewer::Type type )
: SoWinExaminerViewer( parent, name, buildInsideParent, flag, type )
{
// New key binding.
// F3 = Dolly
addFunctionKeyBinding( SoKeyboardEvent::F3, new SoViewingDolly() );
// F4 = Panning
addFunctionKeyBinding( SoKeyboardEvent::F4, new SoViewingTranslation() );
// F5 = X Rotation
addFunctionKeyBinding( SoKeyboardEvent::F5, new SoViewingRotationX() );
// F6 = Y Rotation
addFunctionKeyBinding( SoKeyboardEvent::F6, new SoViewingRotationY() );
// F7 = Z Rotation
addFunctionKeyBinding( SoKeyboardEvent::F7, new SoViewingRotationZ() );
// F9 = Spherical rotation
addFunctionKeyBinding( SoKeyboardEvent::F9, newSoViewingSphericalRotation() );
// Assign new mouse binding.
// Equivalent to F3 = Zoom.
SoKeyboardEvent::Key* spinModifierKeys = new SoKeyboardEvent::Key[2];
spinModifierKeys[0] = SoKeyboardEvent::LEFT_CONTROL;
spinModifierKeys[1] = SoKeyboardEvent::LEFT_SHIFT;
SoMouseButtonEvent::Button* newButton = new SoMouseButtonEvent::Button[1];
newButton[0] = SoMouseButtonEvent::BUTTON1;
addViewingMouseBinding( spinModifierKeys, 2, newButton, 1, new SoViewingDolly() );
// Equivalent to F4 = Translation.
SoKeyboardEvent::Key* panModifierKeys = new SoKeyboardEvent::Key[1];
panModifierKeys[0] = SoKeyboardEvent::LEFT_SHIFT;
SoMouseButtonEvent::Button* panButton = new SoMouseButtonEvent::Button[1];
panButton[0] = SoMouseButtonEvent::BUTTON1;
addViewingMouseBinding( panModifierKeys, 1, panButton, 1, new SoViewingTranslation() );
// Pick Mode
setViewing( FALSE );
}

Custom viewers

Introduction

Since Open Inventor 8.0 SoGuiAlgoViewers API provides an easier way to implement custom viewers. Simple to use, its implementation follows the one used for the Open Inventor viewers. Platform independent, it regroups the common and specific algorithms for the different types of viewers.

Algorithms

SoGuiAlgoViewers is divided into two main sections: the common algorithms and the specific algorithms. Animations are also handled by the API in a transparent way for the application.

Common algorithms

The common algorithm methods are used by each type of viewer. These methods include scene graph management, camera management, draw styles, seek animation and methods to interact with the scene (thumbwheels, methods accessible from the buttons or the popup menu of the viewers). In addition to the algorithms which already existed in standard viewer classes, new ones have been introduced including the capability to do selection or zoom on a portion of the scene.

Specific algorithms

The specific algorithms are grouped by viewer type. They involve mainly animations and camera management.

Creating a viewer

Introduction

In order to create a new viewer only a render area is needed. This provides the application with the possibility to add a separate or embedded GUI, and create a new type of viewer.

Using SoGuiAlgoViewers

In order to use SoGuiAlgoViewers: create an instance of it, set the type of viewer, pass it to your render area and finally call the methods needed. The following code snippet illustrates these points:

C++ :

SoGuiAlgoViewers* algo = new SoGuiAlgoViewers; // Initialization
algo->setViewerType( SoGuiAlgoViewers::Examiner ); // Set the type
m_renderArea = new SoWinRenderArea( this, "RAName", true, true, true, algo );
[...]
m_guiAlgo -> doBoxZoom( xPos1, yPos1, xPos2, yPos2 ); // Zoom on the
// specified area*

Managing events

In order to handle events, an event callback must be registered with the render area. This callback will be used to redirect the events to the appropriate methods that the application may redefine to handle them. To have the event processed by the scene graph (especially when the viewer is in picking mode), it must be sent to the render area. The following code snippet illustrates these points:

C++ :

// Register this callback to receive events from the render area
m_renderArea->setEventCallback( CustomViewer::renderAreaEventCB, this );
[...]
// Skeleton of the callback
SbBool
CustomViewer::renderAreaEventCB( void* userData, Event* anyevent ) {
CustomViewer* customViewer = (CustomViewer*)userData;
switch (anyevent->type())
{
// Redirect the event
}
[...]
// In the method handling the events when the viewer is in picking mode
// Send the event to the scene graph if viewing mode is off
m_renderArea->setEventCallback( NULL, NULL ); // This will prevent
// the event to be sent again to CustomViewer
m_renderArea->sendEvent( anEvent ); // Make the render area process the
// event
m_renderArea->setEventCallback( CustomViewer::renderAreaEventCB, this );

Simple example

The following example illustrates how to use SoGuiAlgoViewers to perform a seek action on the scene graph.

Example : Simple use of SoGuiAlgoViewers SeekExample.h

C++ :

#ifndef SEEK_EXAMPLE_H
#define SEEK_EXAMPLE_H
#include <Inventor/Gui/viewers/SoGuiAlgoViewers.h>
#include <Inventor/Xx/SoXxRenderArea.h> //Xx is the platform(Qt, Xt, Win)
class SeekExample
{
public:
SeekExample();
private:
static SbBool eventCB( void* userData, Event* anyevent );
SoGuiAlgoViewers* m_algo;
SoXxRenderArea* m_renderArea;
};
#endif

SeekExample.cpp

C++ :

#include "SeekExample.h"
SeekExample::SeekExample
{
m_algo = new SoGuiAlgoViewers;
algo->setViewerType( SoGuiAlgoViewers::EXAMINER );
m_renderArea = new SoXxRenderArea( this, "CVRenderArea", true, true, true, m_algo );
m_renderArea->setEventCallback( SeekExample::eventCB, this );
}
SeekExample::eventCB( void* userData, Event* anyevent )
{
SeekExample* sE = ( SeekExample\* )userData;
if ( anyEvent->type() == MouseButtonPress )
{
m_algo->seekToPoint( anyEvent->x(), anyEvent->y() ); // Performs
// the seek animation and position the camera automatically
return TRUE; // Return TRUE because the event has been processed
}
return FALSE; // The event may be processed by the render area
}

A complete and detailed example can be found in $OIVHOME/src/Inventor/examples/Qt4/QtCustomViewer (figure 4-11 & 4-12).

Below are the screen captures of the QtCustomViewer example illustrating the use of the API.

Render Area of the custom viewer

General Issues

The core Open Inventor classes (nodes, actions, sensors, etc.) are almost entirely platform independent. However there are some cases where platform differences must be addressed, either by establishing a convention or by enhancing the classes. The most significant cases are:

  • File portability (specifically byte order and floating point format),
  • Extended input and output (specifically the SoInput and SoOutput classes),
  • Offscreen rendering (specifically the SoOffscreenRenderArea class). These issues are addressed in the following sections.

File Portability

Open Inventor “ascii” format files are inherently portable because they are simply “text” files. The only issue is the minor difference in how a “line” is terminated. In the Unix environment, each line of a text file is terminated by a newline character, also known as the line feed character. In the Win32 environment, many programs still use the DOS convention that each line of a text file is terminated by a carriage return plus a line feed. Open Inventor for Win32 reads both kinds of text files, but always writes files with Unix style line termination (line feed only). Programs to do the (simple) conversion between line termination styles are widely available.

Open Inventor “binary” files face the usual portability issues of byte order and floating point format. Open Inventor for Win32 follows these conventions in reading and writing binary files:

Byte order Same as SGI (“big endian”)
Floating point format IEEE floating point
Numeric values 32 bits

Necessary format conversions are done automatically when reading or
writing a file. Because Open Inventor uses the same conventions on every platform, Open
Inventor binary data files are network transparent. The same file can be
read successfully on any platform without performing any explicit conversion. Because the Open
Inventor binary format is also a very compact representation, the portability conventions make
it ideal for transferring and storing 3D graphics data.

Extended Input and Output

The standard Open Inventor classes, SoInput and SoOutput, can read and write Inventor data from a buffer in memory or a file represented by an stdio file pointer (“FILE *”). Both of these mechanisms are also available in the Win32 environment, but there are several additional requirements. Open Inventor for Win32 can also read and write Inventor data from a file represented by a Win32 file handle or an MFC CArchive object. Win32 file handles are specified using a new method. MFC CArchive objects are handled by new classes derived from SoInput and SoOutput. A CArchive object hides the underlying source or destination, which may be a file, a memory buffer, or an OLE structured storage. Support for OLE structured storage is a requirement for using an Open Inventor program as an OLE server, as the target of OLE drag-and-drop operations, and so on.

In order to allow derivation of new classes from SoInput and SoOutput , these classes were modified
to make (essentially) all of their methods virtual. This change does not affect Open Inventor
applications.

Offscreen Rendering

The Open Inventor SoOffscreenRenderArea class is a very powerful tool for generating bitmap UserGuide_Images of an Open Inventor scene. The bitmap image can be written out to a file or reused within the application as an image or texture map. Arguably, SoOffscreenRenderArea belongs in the Open Inventor component library because it needs to use window system-specific calls to obtain a bitmap (pixmap in X11 terms) that OpenGL can render into. However the system-specific details are hidden from the application.

The standard SoOffscreenRenderArea can write files in SGI’s “.rgb” format and Encapsulated PostScript. We also added the ability to write TIFF, JPEG, JPEG2000, PGX, PNM, Sun Raster, and PNG files, and on Windows platforms, BMP files as well using

C++ :

bool
renderToFile( const SbString& filename ) const

The format of the generated image is then chosen automatically according to the file extension.

A custom reader/writer class can also be used by the SoOffscreenRenderArea using renderToBuffer(). If your application needs more control over creation of an output file, the SoBufferObject can be converted into an SbRasterImage using the appropriate constructor. Once instantiated, the SbRasterImage can be passed as a parameter to the write function of any class inheriting from SoRasterImageRW

If the image size is larger than the OpenGL rendering capabilities (typically 2048 by 2048), SoOffscreenRenderArea renders the image using multi-tile rendering. This allows very large UserGuide_Images to be produced.

Some graphic file formats are much more efficient than others at dealing with large UserGuide_Images. Some formats can be written using bands of tiles, whereas others require the full image to be written all at once, which requires more memory. If you plan to generate very large UserGuide_Images, it would be best to use one of the more efficient file formats. You can use SoRasterImageRW::getWriteCapability to query the write capability of the file format: WRITE_SCANLINES is more efficient, WRITE_FULL_IMAGE is less efficient. This is discussed in the section called “SoRasterImageRW”.

Individual tile buffers can be retrieved as a callback is called after each tile is rendered.

Using SoWin::doIdleTasks

If you’re using SoWinRenderArea or any of its derived classes, e.g., SoWinExaminerViewer, then Open Inventor automatically creates an SoSceneManager which creates a node sensor and attachs it to the root of the scene you specified with setSceneGraph(). When you change the scene graph (and auto-redraw is enabled, which is true by default), the sensor is triggered and the SoSceneManager “schedules” a redraw. This is the same as if your application called the scheduleRedraw() method. It schedules a sensor in the “idle queue”. Conceptually the sensors in the idle queue are triggered when Open Inventor detects that the application is “idle” and then a redraw occurs.

Now the question is: how/when does Open Inventor know that the application is “idle” and process the Open Inventor idle queue?

If you are using SoWin::mainLoop(or nextEvent/ dispatchEvent ), it is handled for you. Otherwise, on Windows at least, it requires a little cooperation from the application. We have packaged the “things to be done when the application is idle” in the method SoWin::doIdleTasks. Calling this method will process the idle queue and so on. If this method is never called, then autoRedraw (automatically redrawing on a scene graph change) may not work.

If you are writing a straight Win32 program, you probably have an explicit Windows message loop in your application. An easy way to detect “idle” is when the message queue is empty. SoWin ’s nextEvent() method does this:

C++ :

DWORD qstatus = GetQueueStatus( QS_ALLINPUT );
if ( qstatus == 0 )
SoWin::doIdleTasks();

before calling GetMessage (because GetMessage blocks when the queue is empty!). This is about the same as calling PeekMessage.

If you are writing an MFC program, it’s easier because MFC has its own idea of what “idle” means. You just override the OnIdle handler in your app class, e.g., CMyApp::OnIdle(), and call SoWin::doIdleTasks in there. If you look at the simple MFC examples (.../src/Inventor/examples/mfc/...) you’ll see this.