This chapter describes the geometry data type and how it is used in the IRIS Explorer environment. It defines the geometry data type and explains how geometry is created in IRIS Explorer. It also describes the interface between IRIS Explorer and Open Inventor(tm), a 3-D graphics development tool, and explains the role of the Open Inventor scene graph in creating more complex geometry.
The API (Application Programming Interface) routines are listed, and examples of user function code for writing modules that produce or manipulate geometry are included.
The
cxGeometry
data type is a root data type, which means it can be specified as a data type
on a port and will pass data between modules. It enables IRIS Explorer to
handle geometry objects by providing a container for Open Inventor scene
graph specifications. Open Inventor is an object-oriented graphics library of
objects and methods used to create interactive 3-D graphics. The IRIS
Explorer
Render
module and other geometry modules draw on Open Inventor technology. The
geometry objects that IRIS Explorer uses to visualize numerical data are
created by connecting nodes to form an Open Inventor scene graph. The scene
graph constitutes the IRIS Explorer geometry object.
IRIS Explorer allows you to manipulate Open Inventor nodes to form
geometry objects through the geometry subroutines in the API. You can output
most of the geometry you need in IRIS Explorer by using the Geometry Library,
which creates Open Inventor objects, in this way. To create geometry in IRIS
Explorer, you need not have Open Inventor installed on your system.
To build a module that reads geometry, that is, that accepts the
cxGeometry
data type on its input port, you need direct access to Open Inventor and its
libraries. You also need Open Inventor if you want to obtain more complex
rendering effects than IRIS Explorer can provide. To write a scene graph with
direct reference to the Open Inventor library, you must have Open Inventor
installed on your system.
You can use Open Inventor with C and C++, but not with Fortran. If you are
programming in Fortran, you must use the IRIS Explorer API subroutines for
all your geometry needs.
This chapter points you toward Open Inventor for creating complex
graphical effects that are outside the scope of IRIS Explorer, but it does
not tell you how to use Open Inventor. For more information, refer to the
The Inventor Mentor: Programming Object-Oriented 3D Graphics with Open
Inventor, Release 2. Addison Wesley, 1994. For information on
obtaining Open Inventor, contact one of the IRIS Explorer Centers.
The
cxGeometry
data type is a simple data structure that transcribes an Open Inventor scene
graph into a linear data stream called the
delta protocol, encoded in an Open Inventor binary
file format. It is opaque to IRIS Explorer users. The scene graph can then be
moved between modules that are capable of processing it. A scene graph is a
hierarchical geometrical construction made of
nodes
that contain specific details about the scene graph, or geometry object.
"Scene graph" is the Open Inventor term, and "geometry object" is the IRIS
Explorer term for visualized data.
The delta protocol is so called because it is possible to convey
information about changes in the composition of the original scene graph.
These changes occur when you fire a module that renders, colors, stretches,
reads, or writes geometry. For example, you may use a widget on an upstream
module that processes geometry to alter the shape or orientation of an object
in the
Render
module. Some other IRIS Explorer modules that process geometry are
ReadGeom,
WriteGeom,
LatToGeom,
PyrToGeom, and
VolumeToGeom.
The data type definition follows, although as specified by the 'closed'
keyword, the contents of this structure are not exposed within the Module
Builder, as modules do not need direct access. The Geometry API routines
manipulate this data structure internally.
Figure
5-1
shows the structure of the
cxGeometry
data type.
A geometry module can be written that accepts non-geometry data but which
creates geometry for output using the IRIS Explorer API routines. A simple
example follows. These routines let you create geometry shapes and provide a
few basic editing functions, such as changing the color of a geometry object,
but they do not let you interpret an incoming delta protocol. To write a
module that accepts and reads geometry on its input port, you must use Open
Inventor. An introduction to Open Inventor scene graphs is given in
Understanding Scene Graphs
and is followed by an example geometry module that illustrates the use of
Open Inventor. If you plan to use only the simple IRIS Explorer API to create
geometry, you do not need to understand how Inventor represents scenes.
However, a rudimentary knowledge of how Inventor works may help you
understand how geometry is manipulated in IRIS Explorer.
To illustrate how to use the IRIS Explorer API to create geometry in a
module, here is a simple module, that creates some line segments. It has only
a geometry output port. The user function for the module resides in
$EXPLORERHOME/src/MWGcode/Geometry/C++/LineSegment.C. The Fortran
version is in
$EXPLORERHOME/src/MWGcode/Geometry/Fortran/LineSegment.f. Test
the module by connecting it to a Render module, and selecting
Fire Now on its pop-up menu (as the module has no input ports,
it will not fire of its own accord).
These geometry API routines are introduced in the example:
A scene graph is the Inventor term for a hierarchical, 3-D description of
scene data. It consists of an ordered collection of nodes, each of which
defines a specific shape (or geometry), property, or grouping aspect of the
scene. The hierarchy is created by adding sublevels of nodes to the top-level
or root node in a scene graph, creating a directed acyclic graph.
Figure
5-2
shows a simple scene graph. The heavy line running from the root node down
the right-hand branch to the shape node shows the hierarchical path or
progression in the graph.
The node
(footnote)
is the basic building block for creating scene graphs in Inventor. Each node
holds a piece of information, such as a shape description, a geometric
transformation, a camera position, or a light source. Each scene graph has a
root
node, which is the first node you create. You can apply actions to a scene
graph, such as rendering, picking, and writing to a file. The IRIS Explorer
Render
module renders numerical data in the form of a scene graph.
Nodes fall into three categories: shape nodes, which represent 3-D
geometric objects; property nodes, which represent qualitative values, such
as appearance; and group nodes, which collect single nodes into graphs.
Each node has a set of fields that describe the parameters of the node.
For example, a node defining a point light source has three fields,
intensity, color, and location. Each of these fields can be given a value
(location) or range of values (intensity). The order in which nodes are
arranged is important because it determines how the values that each node
contains are acted upon.
Calls to the Geometry API create Inventor nodes and simultaneously transcribe
the node data into the
delta protocol
stored in the
cxGeometry
data buffer. Inventor classes can be used directly to create a scene graph
within an IRIS Explorer module. To move this scene graph to another module it
must still be transcribed into the
cxGeometry
data buffer.
The routine
cxGeoInventorDefine
is used to perform the transcription of the root node and all nodes beneath
it in the hierarchy. This call will also attach the given root node to the
scene graph within the geometry API - when
cxGeoInit
is called a root node is always created. Standard Open Inventor binary
transcription is performed using objects of classes
SoTranSender
and
SoOutput.
A set of Open Inventor node classes have been implemented for use solely
within IRIS Explorer. These classes, whose names are prefixed
cxSo, for example
cxSoIndexedFaceSet, have identical functionality to the corresponding
standard Inventor node classes with
So
names. The difference is that they use new field classes derived from the
standard Open Inventor multi-valued field classes. These new field classes,
again prefixed
cxSo, for example
cxSoMFLong, store their data in the IRIS Explorer shared memory arena,
when available. See
Understanding Reference Counting
for further discussion of shared memory.
These
cxSo
nodes are used when creating geometry within the Geometry API. To obtain the
performance advantage of using shared memory when moving scene graphs between
modules you should create nodes with these classes when using Open Inventor
directly within IRIS Explorer modules. Simply replace the declaration of an
So
node class with the corresponding
cxSo
class.
To illustrate the use of Inventor, including the cxSo nodes, within an
IRIS Explorer module, here is an example that creates a set of polygons. The
classes cxSoCoordinate3, cxSoMaterial and cxSoNormal are used, therefore the
appropriate header files in
cx/nodes
are included. The module has a geometry output port. The user function for
the module resides in
$EXPLORERHOME/src/MWGcode/Geometry/C++/FaceSet.C. Test
the module by connecting it to a Render module, and selecting
Fire Now on its pop-up menu (as the module has no input ports,
it will not fire of its own accord).
The cxSo node classes that are available are listed below, together with the
cxSo field class used for the attribute data of the node.
The transcription of the Inventor Scene Graph into the Geometry data
buffer differs for cxSo nodes. It is not necessary to transcribe all the
field data into the binary data stream, only the pointer to memory is added
when shared memory is appropriate for the module to module connection. It is
this that gives the performance advantage when moving scene graphs between
modules. For this reason it is necessary to identify which port the
cxGeometry
data will be placed on before making further cxGeo calls, so that the correct
transcription method can be used.
Table
5-1
lists the cxSo node classes and referenced cxSo field classes.
Open Inventor must be used in modules that receive geometry on input ports.
An Inventor
receiver object
is required to decode the incoming data from a specific upstream module and
create the resulting Scene Graph. The API function
cxGeoReceiverNew
creates this object, and
cxGeoReceive
performs the decoding from the given
cxGeometry
object. The incoming scene graph is attached to a parent node that has been
previously created.
A different receiver object should be used for each geometry connection.
This prevents data updates from one module being passed to nodes that contain
data from another module. The parent node/receiver object pairs control the
distribution of new data to the correct nodes.
The
cxGeometry
data type, though defined in the IRIS Explorer typing language, can be
considered as a C structure. However the
cxGeometry
data type is usually accessed internally via the geometry API functions. It
should not be necessary for module user code to access the data structure
directly. The type declaration resides in the header file
$EXPLORERHOME/include/cx/cxGeometry.h.
The
cxGeometry
data type structure is defined as follows:
The
cxGeometry
data type has its own API subroutine library that enables you to write simple
IRIS Explorer modules that output scene graphs without manipulating Open
Inventor code. You can create and manipulate the geometry objects by using
the geometry subroutines listed below. To create more complex modules, you
can use Open Inventor directly.
The geometry subroutines are described in the
IRIS Explorer Reference
Pages.
Table
5-2
lists the subroutines and briefly defines each one.
The examples that follow show the use of both IRIS Explorer subroutines
and Open Inventor classes to create and manipulate geometry in modules. The
code examples are located in the
$EXPLORERHOME/src/MWGcode/Geometry/*
subdirectories.
This example is the Fortran version of the previous C++ example that
creates some line segments and outputs them as geometry. The code is in
$EXPLORERHOME/src/MWGcode/Geometry/Fortran/LineSegment.f. Test
the module by connecting it to a Render module, and selecting
Fire Now on its pop-up menu (as the module has no input ports,
it will not fire of its own accord).
The following example creates spheres, lines and polygons. The code is in
$EXPLORERHOME/src/MWGcode/Geometry/C/PolySegment.c
and
$EXPLORERHOME/src/MWGcode/Geometry/Fortran/PolySegment.f. Test
it by attaching GenerateColormap to its input port, and
Render to its output port.
Figure
5-3
shows what the module output looks like.
Here are two examples of a user function showing how you can use Open
Inventor to create and display geometry objects. Neither example has a
Fortran equivalent because Open Inventor has no Fortran API.
This is a simple example of how to use the Open Inventor library, written
in C++. The function wraps an image onto a sphere. The code is in
$EXPLORERHOME/src/MWGcode/Geometry/C++/Texture.C
Test it by attaching Render to its output port, and typing the name
for a texture file in the slot named Texture Filename. One
such file is $EXPLORERHOME/lib/reconstruction.bw.
This is a reasonably small module, written in C++, that implements a
geometry renderer using the Open Inventor library. The code is in
$EXPLORERHOME/src/MWGcode/Geometry/C++/SimpleRender.C
For simplicity, several limitations have been accepted:
The Geometry Data Type
closed shared root typedef struct {
short id;
long count; */ length of the data stream in bytes */
char data[count]; /* the delta protocol */
long numBuffers;
cxMemory buffers[numBuffers]; /* Shared memory data */
} cxGeometry;
Figure 5-1 Schematic Structure of the Geometry Data Type
Creating Geometry Modules
An Example Geometry Module
/* This example creates some line segments and */
/* outputs them as geometry */
/* */
#include <cx/DataTypes.h>
#include <cx/DataAccess.h>
#include <cx/Geometry.h>
#include <cx/PortAccess.h>
static float p[] = {
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 0.0, 1.0,
0.0, 0.0, 1.0
};
static long index[] = {
0, 1, 2, 3, 0, 7, 6, 5, 4, 7, -1,
1, 6, -1,
2, 5, -1,
3, 4, -1
};
extern "C" void line(cxGeometry **geom)
{
/* initialize geometry library once only */
static int flag = 1;
if ( flag )
{
flag = 0;
cxGeoInit();
}
/* Create a new Geometry data type*/
*geom = cxGeoNew();
/* Make the buffer in this Geometry data be used to store the
geometry created by following geometry creation calls i.e.
the cxGeoLinesDefine call */
cxGeoBufferSelect(*geom);
/* Get the port for Geometry output */
int port = cxOutputPortOpen("Output");
/* Associate the Geometry data with this port */
cxGeoBufferPortSet(port);
/* set the current geometry object to be the root object and then
delete all geometry created by previous module firings */
cxGeoRoot();
cxGeoDelete();
/* Create a new geometry object */
cxGeo id = cxGeoLinesDefine(8, p, 20, index);
/* Close the buffer in the Geometry data, in preparation for
it to be output on the port */
cxGeoBufferClose(*geom);
}
Understanding Scene Graphs
Figure 5-2 Inventor Scene Graph
Using Open Inventor in Geometry Modules
Creating Geometry
// This example creates a Face Set using the Open Inventor
// library and the Explorer extension classes whose field
// data is stored in Explorer shared memory
#include <cx/DataAccess.h>
#include <cx/DataTypes.h>
#include <cx/Geometry.h>
#include <cx/PortAccess.h>
#include <cx/nodes/cxSoCoordinate3.h>
#include <cx/nodes/cxSoMaterial.h>
#include <cx/nodes/cxSoNormal.h>
#include <Inventor/nodes/SoFaceSet.h>
#include <Inventor/nodes/SoNormalBinding.h>
#include <Inventor/nodes/SoSeparator.h>
// Eight polygons. The first four are triangles
// The second four are quadrilaterals for the sides.
static const float vertices[28][3] =
{
{ 0, 9, 0}, {-2,6, 2}, { 2,6, 2}, //front tri
{ 0, 9, 0}, {-2,6,-2}, {-2,6, 2}, //left tri
{ 0, 9, 0}, { 2,6,-2}, {-2,6,-2}, //rear tri
{ 0, 9, 0}, { 2,6, 2}, { 2,6,-2}, //right tri
{-2, 6, 2}, {-4,0, 4}, { 4,0, 4}, { 2,6, 2}, //front quad
{-2, 6,-2}, {-4,0,-4}, {-4,0, 4}, {-2,6, 2}, //left quad
{ 2, 6,-2}, { 4,0,-4}, {-4,0,-4}, {-2,6,-2}, //rear quad
{ 2, 6, 2}, { 4,0, 4}, { 4,0,-4}, { 2,6,-2} //right quad
};
// Number of vertices in each polygon:
static int32_t numvertices[8] = {3, 3, 3, 3, 4, 4, 4, 4};
// Normals for each polygon:
static const float norms[8][3] =
{
{0, .555, .832}, {-.832, .555, 0}, //front, left tris
{0, .555, -.832}, { .832, .555, 0}, //rear, right tris
{0, .0739, .9973}, {-.9972, .0739, 0},//front, left quads
{0, .0739, -.9973}, { .9972, .0739, 0},//rear, right quads
};
extern "C" {
void makeFaceSet(
cxGeometry **geo)
{
// initialize geometry api once only
// this creates a root node
static int first = 1;
if ( first )
{
first = 0;
cxGeoInit();
}
// Create a new Geometry data type
*geo = cxGeoNew();
// Make the buffer in this Geometry data be used to store the
// geometry created
cxGeoBufferSelect(*geo);
// Get the port for Geometry output and associate
// the Geometry data with this port
cxGeoBufferPortSet(cxOutputPortOpen("Face Set"));
// set the current geometry object to be the root node and
// delete all geometry created by previous module firings
// below the root node
cxGeoRoot();
cxGeoDelete();
// create the Inventor Scene using the Explorer nodes
// so that their field data is stored in shared memory
SoSeparator *topNode= new SoSeparator();
topNode->ref();
// Define the normals used:
cxSoNormal *myNormals = new cxSoNormal;
myNormals->vector.setValues(0, 8, norms);
topNode->addChild(myNormals);
SoNormalBinding *myNormalBinding = new SoNormalBinding;
myNormalBinding->value = SoNormalBinding::PER_FACE;
topNode->addChild(myNormalBinding);
// Define material for topNode
cxSoMaterial *myMaterial = new cxSoMaterial;
myMaterial->diffuseColor.setValue(.4, .4, .4);
topNode->addChild(myMaterial);
// Define coordinates for vertices
cxSoCoordinate3 *myCoords = new cxSoCoordinate3;
myCoords->point.setValues(0, 28, vertices);
topNode->addChild(myCoords);
// Define the FaceSet
SoFaceSet *myFaceSet = new SoFaceSet;
myFaceSet->numVertices.setValues(0, 8, numvertices);
topNode->addChild(myFaceSet);
// Add this Scene Graph to the Geometry api's root node
// and add to the Geometry buffer
cxGeoInventorDefine(topNode);
// Decrement reference count as it is now referenced by root node
topNode->unref();
// Close the buffer in the Geometry data, in preparation for
// it to be output on the port
cxGeoBufferClose(*geo);
}
}
IRIS Explorer Node Classes
cxSo Node
Attribute Name
cxSo Field
cxSoColorIndex
index
cxSoMFLong
cxSoCoordinate3
point
cxSoMFVec3f
cxSoCoordinate4
point
cxSoMFVec4f
cxSoIndexedFaceSet
cxSoIndexedLineSet
cxSoIndexedShape
materialIndex
cxSoMFLong
normalIndex
cxSoMFLong
textureCoordIndex
cxSoMFLong
cxSoIndexedTriangleStripSet
cxSoMaterial
ambientColor
cxSoMFColor
diffuseColor
cxSoMFColor
specularColor
cxSoMFColor
emissiveColor
cxSoMFColor
shininess
cxSoMFFloat
transparency
cxSoMFFloat
cxSoMaterialIndex
ambientIndex
cxSoMFLong
diffuseIndex
cxSoMFLong
specularIndex
cxSoMFLong
shininess
cxSoMFFloat
transparency
cxSoMFFloat
cxSoNormal
vector
cxSoMFVec3f
cxSoPackedColor
rgba
cxSoMFULong
Receiving Geometry
Data Type Declaration
typedef struct cxMemory {
cxDataCtlr ctlr;
long n;
unsigned char *mem;
} cxMemory;
typedef struct cxGeometry {
cxDataCtlr ctlr;
short id;
long count;
unsigned char *data;
long numBuffers;
cxMemory **buffers;
} cxGeometry;
The Geometry API Routines
Subroutine
Purpose
cxGeoNew
Creates a new IRIS Explorer geometry data structure
cxGeoInit
Initializes the IRIS Explorer Geometry Library
cxGeoPointsDefine
Creates a set of points
cxGeoLinesDefine
Creates a set of unclosed polylines
cxGeoPolysDefine
Creates a set of polygons
cxGeoSplineDefine
Creates a NURB spline
cxGeoTrisDefine
Creates a set of triangle meshes
cxGeoPatchDefine
Creates a NURBS patch
cxGeoSpheresDefine
Creates a set of spheres
cxGeoConesDefine
Creates a set of cones
cxGeoCylindersDefine
Creates a set of cylinders
cxGeoGridDefine
Creates a grid geometry object
cxGeoTextDefine
Creates a text object
cxGeoOctreeDefine
Creates a volume object rendered as an octree
cxGeoInventorDefine
Creates an entire Open Inventor scene graph
cxGeoNormalAdd
Adds normals to the current geometry object
cxGeoColorAdd
Adds colors to the current geometry object
cxGeoABGRAdd
Adds packed (32-bit) colors to the current geometry object
cxGeoComplexityAdd
Specifies the level of rendering detail
cxGeoLabelAdd
Adds a label to the current geometry object
cxGeoStyleAdd
Adds a drawing style to the current geometry object
cxGeoTransparencyAdd
Adds transparency to the current geometry object
cxGeoLightModelAdd
Specifies the lighting model for the current geometry object
cxGeoXformPop
Makes the current object the parent of the current transform group
cxGeoXformPush
Groups objects under a parent hierarchy object
cxGeoIdentity
Resets the transform on the current object
cxGeoTranslate
Translates the current geometry object
cxGeoRotate
Rotates the current geometry object
cxGeoScale
Scales the current geometry object
cxGeoMatrixCat
Applies an arbitrary 4x4 transform to the object
cxGeoReceive
Receives IRIS Explorer input data for transcription
cxGeoFocus
Specifies the current object or transform for editing
cxGeoRoot
Makes the root object the current object
cxGeoDelete
Makes the root object the current object
cxGeoBufferClose
Prepares a geometry buffer to be sent
cxGeoBufferPortSet
Associates a port with the current geometry buffer
cxGeoBufferSelect
Specifies a geometry buffer for subsequent scene edits
Code Examples
Modules using the Geometry API
Creating Line Segments
C This module creates some line segments and outputs them as geometry
subroutine linef ( h_geom )
#if defined(IS_64BIT)
integer*8 h_geom
integer*8 index(20)
#else
integer h_geom
integer index(20)
#endif
C
C Please complete the user function by adding subprogram lines here.
C
include '/usr/explorer/include/cx/DataAccess.inc'
include '/usr/explorer/include/cx/Geometry.inc'
include '/usr/explorer/include/cx/PortAccess.inc'
integer flag
real p(24)
integer port, id
data flag/1/
data p/0.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 1.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0/
data index/0, 1, 2, 3, 0, 7, 6, 5, 4, 7, -1,
+ 1, 6, -1,
+ 2, 5, -1,
+ 3, 4, -1/
C initialize geometry library once only
if ( flag .eq. 1 ) then
flag = 0
call cxGeoInit()
endif
C
C Create a new Geometry data type
h_geom = cxGeoNew()
C
C Make the buffer in this Geometry data be used to store the
C geometry created by following geometry creation calls i.e.
C the cxGeoLinesDefine call
call cxGeoBufferSelect(h_geom)
C
C Get the port for Geometry output
port = cxOutputPortOpen("Output")
C
C Associate the Geometry data with this port
call cxGeoBufferPortSet(port)
C
C set the current geometry object to be the root object and then
C delete all geometry created by previous module firings
call cxGeoRoot()
call cxGeoDelete()
C
C Create a new geometry object
id = cxGeoLinesDefine(8,p,20,index)
C
C Close the buffer in the Geometry data, in preparation for
C it to be output on the port
call cxGeoBufferClose(h_geom)
C
RETURN
END
Creating More Geometry Objects
C Version:
/* This example uses the API to create geometry and attach attributes
* to the geometry
* The module data wrapper is not used in this module,
port acces is therefore via api calls */
#include <stdio.h>
#include <cx/DataTypes.h>
#include <cx/DataAccess.h>
#include <cx/PortAccess.h>
#include <cx/UserFuncs.h>
#include <cx/Geometry.h>
#include <cx/Lookup.h>
float lins[] = {0.,0.,0., 0.,0.,1., 0.,1.,1., 0.,1.,0.,
1.,0.,0., 1.,0.,1., 1.,1.,1., 1.,1.,0. };
long conn[] = {0,1,2,3,0,4,5,6,7,4,-1,1,5,-1,2,6,-1,3,7,-1};
long conn2[] = {0,1,5,4,-1,2,3,7,6,-1};
void display()
{
cxLattice *cmap; /* Color map */
cxGeometry *geo;
cxLookup *clut;
float col[4],sphs[10][3],rads[10],x;
int i,j;
/* Get lattice for colormap from port and create lookup table */
cmap = (cxLattice*)cxInputDataGet(cxInputPortOpen("colormap"));
if(cmap == NULL){
printf("geometry: no color map present\n");
return;
}
clut = cxLookupCreate(cmap,1);
/* Create Geometry data type and set its buffer for the
output of geometry */
geo = cxGeoNew();
if( cxDataAllocErrorGet() ) goto cleanupGeo;
cxGeoBufferSelect(geo);
/* set the port on which this geometry will be sent */
cxGeoBufferPortSet(cxOutputPortOpen("geom"));
/* Delete all geometry created by previous module firing */
cxGeoRoot();
if( cxDataAllocErrorGet() ) goto cleanupSelected;
cxGeoDelete();
if( cxDataAllocErrorGet() ) goto cleanupSelected;
/* Set radii and positions of spheres and create the spheres*/
for(i=0;i<10;i++){
for(j=0;j<3;j++){
sphs[i][j] = i;
}
rads[i] = i / 10.0 + 0.01;
}
cxGeoSpheresDefine(5,sphs[0],rads);
if( cxDataAllocErrorGet() ) goto cleanupSelected;
x = 0.8;
cxLookupInterp(clut,&x,(void *)col);
cxGeoColorAdd(1,col,CX_GEO_PER_OBJECT);
if( cxDataAllocErrorGet() ) goto cleanupSelected;
/* Create the lines of the cube */
cxGeoLinesDefine(8,lins,20,conn);
if( cxDataAllocErrorGet() ) goto cleanupSelected;
x = 0.5;
cxLookupInterp(clut,&x,(void *)col);
cxGeoColorAdd(1,col,CX_GEO_PER_OBJECT);
if( cxDataAllocErrorGet() ) goto cleanupSelected;
/* Create the polygons of the cube */
cxGeoPolysDefine(8,lins,10,conn2);
if( cxDataAllocErrorGet() ) goto cleanupSelected;
x = 0.2;
cxLookupInterp(clut,&x,(void *)col);
cxGeoColorAdd(1,col,CX_GEO_PER_OBJECT);
if( cxDataAllocErrorGet() ) goto cleanupSelected;
/* Close the buffer of the geometry data - ready for
sending on the port */
cxGeoBufferClose(geo);
cxOutputDataSet(cxOutputPortOpen("geom"),geo);
cxLookupDestroy(clut);
return;
/* Handle error conditions */
cleanupSelected:
cxGeoBufferClose(geo);
cleanupGeo:
cxDataRefDec(geo);
cxLookupDestroy(clut);
return;
}
/* Function specified as an 'Init Hook Function'
in the Module Builder Build/Hook Functions option */
void geom_init()
{
/* Initialise the geometry api first time the module fires */
cxGeoInit();
}
Fortran Version:
C This example uses the API to create geometry and attach attributes
C to the geometry
C
C
SUBROUTINE DSPLAY(CMAP,GEO)
INCLUDE '/usr/explorer/include/cx/DataAccess.inc'
INCLUDE '/usr/explorer/include/cx/Lookup.inc'
INCLUDE '/usr/explorer/include/cx/PortAccess.inc'
C
C .. Parameters ..
INTEGER CX_GEO_PER_OBJECT
PARAMETER (CX_GEO_PER_OBJECT=1)
C .. Scalar Arguments ..
#if defined(IS_64BIT)
INTEGER*8 CMAP, GEO, CLUT
INTEGER*8 CONN(20), CONN2(10)
#else
INTEGER CMAP, GEO, CLUT
INTEGER CONN(20), CONN2(10)
#endif
C .. Local Scalars ..
REAL X
INTEGER I, IER, J
LOGICAL FIRST
C .. Local Arrays ..
REAL COL(4), LINS(3,8), RADS(10), SPHS(3,10)
C .. External Subroutines ..
EXTERNAL CXDATAREFDEC, CXGEOBUFFERCLOSE,
* CXGEOBUFFERPORTSET, CXGEOBUFFERSELECT,
* CXGEOCOLORADD, CXGEODELETE, CXGEOINIT,
* CXGEOLINESDEFINE, CXGEOPOLYSDEFINE, CXGEOROOT,
* CXGEOSPHERESDEFINE, CXLOOKUPDESTROY
C .. External Functions ..
EXTERNAL CXDATAALLOCERRORGET, CXGEONEW, CXLOOKUPCREATE,
* CXLOOKUPINTERP, CXOUTPUTPORTOPEN
C .. Intrinsic Functions ..
INTRINSIC REAL
C .. Data statements ..
DATA LINS/0., 0., 0., 0., 0., 1., 0., 1., 1., 0., 1.,
* 0., 1., 0., 0., 1., 0., 1., 1., 1., 1., 1., 1.,
* 0./
DATA CONN/0, 1, 2, 3, 0, 4, 5, 6, 7, 4, -1, 1, 5, -1,
* 2, 6, -1, 3, 7, -1/
DATA CONN2/0, 1, 5, 4, -1, 2, 3, 7, 6, -1/
DATA FIRST/.TRUE./
C .. Executable Statements ..
C
C Initialise the geometry api first time the module fires
IF (FIRST) THEN
CALL CXGEOINIT
FIRST = .FALSE.
END IF
C
C Create color lookup table from input lattice
CLUT = CXLOOKUPCREATE(CMAP,1)
C
C Create Geometry data type and set its buffer for the
C output of Geometry
GEO = CXGEONEW()
IF (CXDATAALLOCERRORGET().NE.0) GO TO 80
CALL CXGEOBUFFERSELECT(GEO)
C set the port on which this geometry will be sent
CALL CXGEOBUFFERPORTSET(CXOUTPUTPORTOPEN('geom'))
C
C Delete all geometry created by previous module firing
CALL CXGEOROOT
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
CALL CXGEODELETE
C
C Set radii and positions of spheres and create the spheres
C
DO 40 I = 1, 10
DO 20 J = 1, 3
SPHS(J,I) = I
20 CONTINUE
RADS(I) = REAL(I)/10.0
40 CONTINUE
C
CALL CXGEOSPHERESDEFINE(5,SPHS,RADS)
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
X = 0.8
IER = CXLOOKUPINTERP(CLUT,X,COL)
CALL CXGEOCOLORADD(1,COL,CX_GEO_PER_OBJECT)
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
C
C Create the lines of the cube
C
CALL CXGEOLINESDEFINE(8,LINS,20,CONN)
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
X = 0.5
IER = CXLOOKUPINTERP(CLUT,X,COL)
CALL CXGEOCOLORADD(1,COL,CX_GEO_PER_OBJECT)
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
C
C Create the polygons of the cube
C
CALL CXGEOPOLYSDEFINE(8,LINS,10,CONN2)
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
X = 0.2
IER = CXLOOKUPINTERP(CLUT,X,COL)
CALL CXGEOCOLORADD(1,COL,CX_GEO_PER_OBJECT)
IF (CXDATAALLOCERRORGET().NE.0) GO TO 60
C
C Close the buffer of the geometry data - ready for
C sending on the port
C
CALL CXGEOBUFFERCLOSE(GEO)
C
CALL CXLOOKUPDESTROY(CLUT)
RETURN
C
C memory allocation error cleanup
C
60 CONTINUE
CALL CXGEOBUFFERCLOSE(GEO)
80 CONTINUE
CALL CXDATAREFDEC(GEO)
CALL CXLOOKUPDESTROY(CLUT)
RETURN
END
Figure 5-3 Output from Geometry Example
Creating Modules with Open Inventor Code
Texturing a Sphere
// This example creates a sphere and wraps an image
// onto it, using the Open Inventor library. This
// Inventor scene graph is then added to the Explorer
// Geometry buffer.
#include <cx/DataAccess.h>
#include <cx/DataTypes.h>
#include <cx/Geometry.h>
#include <cx/PortAccess.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoTexture2.h>
#include <Inventor/nodes/SoSeparator.h>
#include <cx/nodes/cxSoMaterial.h>
extern "C" {
void makeSphere (
float radius,
char *texfile,
cxGeometry * * geo )
{
// initialize geometry api once only
// this creates a root node
static int first = 1;
if ( first )
{
first = 0;
cxGeoInit();
}
// Create a new Geometry data type
*geo = cxGeoNew();
// Make the buffer in this Geometry data be used to store the
// geometry created
cxGeoBufferSelect(*geo);
// Get the port for Geometry output and associate
// the Geometry data with this port
cxGeoBufferPortSet(cxOutputPortOpen("Texture Geometry"));
// set the current geometry object to be the root node and
// delete all geometry created by previous module firings
// below the root node
cxGeoRoot();
cxGeoDelete();
// create the Inventor Scene
SoGroup *topNode = new SoSeparator();
topNode->ref();
SoSphere *sph = new SoSphere();
SoTexture2 *tex = new SoTexture2();
// Use the Explorer Material class so that its data is
// stored in shared memory
cxSoMaterial *m = new cxSoMaterial();
m->diffuseColor.setValue(1.0,1.0,1.0);
tex->filename.setValue(texfile);
sph->radius = radius;
topNode->addChild(tex);
topNode->addChild(m);
topNode->addChild(sph);
// Add this Scene Graph to the Geometry api's root node
// and add to the Geometry buffer
cxGeoInventorDefine(topNode);
// Decrement reference count as it is now referenced by root node
topNode->unref();
// Close the buffer in the Geometry data, in preparation for
// it to be output on the port
cxGeoBufferClose(*geo);
}
}
A Simple Renderer
/*
* This example creates a simple render module using
* Inventor code and is an example of a module that
* receives Geometry data.
*
*/
#include <X11/Intrinsic.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoGroup.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoShapeHints.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <cx/DataAccess.h>
#include <cx/DataTypes.h>
#include <cx/Geometry.h>
#include <cx/PortAccess.h>
#include <cx/UserFuncs.h>
#include <cx/XtArea.h>
Widget top; /* top level widget for drawing area */
SoGroup *group; /* root for incoming geometry */
cxGeoReceiver receiver; /* receiver object for incoming geometry */
SoXtViewer *viewer; /* Inventor viewer */
extern "C" void renderlite(
cxGeometry *geo, /* incoming geometry */
int geoFlag, /* nonzero if geometry is new */
long window, /* window id of drawing area */
int windowFlag) /* nonzero if window is new */
{
static int first = 1; /* initialization flag */
if ( first && window )
{
/* reset initialization flag */
first = 0;
/* initialize geometry api once only -
this initialises cxSo classes so that they
are recognised in incoming geometry */
cxGeoInit();
/* create top level widget for drawing area */
top = cxXtAreaInitialize();
/* initialize Inventor for use with Xt*/
SoXt::init(top);
/* create the environment */
SoGroup *root = new SoSeparator();
root->ref();
/* shape hints */
SoShapeHints *n1 = new SoShapeHints();
n1->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
root->addChild(n1);
/* create the node for the incoming geometry */
group = new SoGroup();
root->addChild(group);
/* create the receiver object */
receiver = cxGeoReceiverNew(group);
/* create the viewer */
viewer = new SoXtExaminerViewer();
viewer->setSceneGraph(root);
viewer->setSize(SbVec2s(100,100));
viewer->show();
/* attach the viewer widget to the Explorer Form widget */
Widget vw = viewer->getWidget();
XtVaSetValues(vw,
XmNtopAttachment,XmATTACH_FORM,
XmNbottomAttachment,XmATTACH_FORM,
XmNrightAttachment,XmATTACH_FORM,
XmNleftAttachment,XmATTACH_FORM,
NULL);
/* attach widget to window */
cxXtAreaAttach(top,window);
}
if ( windowFlag ) /* window has changed state or size */
cxXtAreaResize(top,window);
if ( geoFlag ) /* new geometry has arrived */
{
cxGeoReceive(geo,receiver);
viewer->viewAll();
}
}
Last modified: Thu Jun 5 11:10:25 1997
[ Documentation Home ]