Appendix B. An Introduction to the C API

Read this chapter if you will be programming in C! If you are unfamiliar with object-oriented programming, you should first read Appendix A, which introduces some of the features of C++ and some of the conceptual underpinnings of the Open Inventor C interface.

Though the C++ syntax is different, the concepts described in earlier chapters of this book still apply to the C implementation of Open Inventor. As you read the rest of this book, you can refer to this appendix as necessary to translate the C++ examples into C. If you have purchased Open Inventor, you can also compare the C version of each online example program to the C++ version in this book. See the release notes for information on finding and using the online example programs and for details on how to compile and link an Inventor program written in C.

The following sections explain the differences between the Open Inventor C and C++ interfaces. They discuss these topics:

The Open Inventor C interface is generated by an automated translation program. This interface defines a C structure for each C++ class, which is actually a direct mapping to the C++ class. This structure is defined in the C include file for the class. Fields within the C structure are either hidden or public. Public fields (member variables) are documented in the reference manual page for each class. Hidden fields (private member variables) are named pad[]. You should not modify hidden fields.

The sample code fragments in these sections are drawn from Chapter 2.

Naming C Functions

The name of each C function is the C++ member function prefixed by the class name. Suppose there were a class named SoGenericType, with a member function doOp(). The C name for that function would be SoGenericTypeDoOp(). The object to be operated upon by the member function appears as the first argument to the C version of the function. A C prototype for our generic hypothetical function would look something like this:

SoGenericTypeDoOp(SoGenericType *);

To give a more specific example, the function to add a node to a group looks like this in C++ and C:

C++:

root->addChild(material);
C:
SoGroupAddChild(root, (SoNode *) material);

The C function name has the prefix SoGroup. Since addChild() is a member function of SoGroup, the first argument to the C function must be a pointer to an object of type SoGroup. Since addChild() expects a pointer to an object of type SoNode as its second argument, use a cast to SoNode * if you need to.

Now, suppose that you want to apply the function doOp() to a member of a subclass of SoGenericType, like SoGenericSubType. The C subclasses inherit all the member functions of their parent classes in the form of macro functions. The macros simply call the parent class function and cast the object to the parent's object type. The names of the inherited macro functions, though, are prefixed with the name of the subclass, not the parent class. So the C function name for doOp() would be SoGenericSubTypeDoOp(). You could use the parent class funtion, SoGenericTypeDoOp(), if you cast the object to SoGenericType.

In the real Inventor example addChild(), you're more likely to be adding children to subclasses of SoGroup. For example, the C macro function to add a child node to a separator is

C:

SoSepAddChild(separator, (SoNode *) material);

Abbreviating C Function Names

Here is another example of an Open Inventor C function:

C++:

viewer = new SoXtExaminerViewer(myWindow);
viewer->setSceneGraph(root);
C:
viewer = SoXtExamVwrCreateStd(myWindow, NULL);
SoXtExamVwrSetScene(viewer, (SoNode *) root);

The C++ function setSceneGraph() is a member of the class SoXtRenderArea, but the viewer is a pointer to type SoXtExamVwr. So the C macro function name is prefixed with SoXtExamVwr and has a pointer to an object of that type as its first argument.

But as you can see, the C function name is abbreviated. The function in the preceding example, if it were unabbreviated, would be SoXtExaminer-ViewerSetScene(), which is long and unwieldy. Table B-1 lists the abbreviations used in the C function names. Whenever the C++ function name contains one of the strings listed in the table, the corresponding C function uses the abbreviation in the second column.

Table B-1. C Function Name Abbreviations

C++ Function Name

Abbreviation

Action

Act

Attenuation

Atten

Binding

Bind

BoundingBox

BBox

Button

Btn

Callback

CB

Camera

Cam

Catalog

Cat

Character

Char

Color

Col

Component

Comp

Cylinder

Cyl

Decoration

Decor

Detail

Dtl

Direction

Dir

Directory

Dir

Editor

Ed

Environment

Env

Event

Ev

Examiner

Exam

FaceSet

FSet

Function

Func

Highlight

HL

Index

Ind (Indexed->Index)

Input

In

Integer

Int

Keyboard

Key

Light

Lgt

LineSet

LSet

Location

Loc

Locator

Loc

Manager

Mgr

Manipulator

Mnp

Material

Mtl

Matrix

Mx

Normal

Norm

Orthographic`

Ortho

Output

Out

Perspective

Persp

Plane

Pln

Point

Pt

PointSet

PSet

Pointer

Ptr

Position

Pos

Primitive

Prim

Profile

Prof

Projector

Proj

QuadMesh

QMesh

RenderArea

RA

Rotate

Rot

Searching

Search

Section

Sect

Slider

Sldr

String

Str

Sphere

Sph

Texture

Tex

Tolerance

Tol

Transform

Xf

Translate

Xlate

TriangleStripSet

TSet

Vec

V(Vec3f-> V3f)

Vertex

Vtx

Viewer

Vwr

Visibility

Vis

Wheel

Whl

Window

Win


Creating and Deleting Objects from C

The C versions of constructors and destructors are named following a convention slightly different from the one for most member functions. The C constructor for an object of our imaginary type SoGenericType would be SoGenericTypeCreate(). This example shows the C++ and C constructors for the SoSeparator type:

C++:

SoSeparator *root = new SoSeparator();
C:
SoSep *root;
root = SoSepCreate();

Destructors are named similarly. A destructor for an object of type SoGenericType would be SoGenericTypeDelete(). To delete a viewer, for example, you might call SoXtExamVwrDelete(viewer). To delete nodes and groups, you use functions that unreference the node or group, instead of using destructors. See the discussion in Chapter 3 for details on deleting nodes.

Overloaded C++ Methods

The C++ language allows more than one method of a class to have the same method name, as long as the lists of arguments to the methods are different. This cabability is not provided by the C language, so different function names must be made for each identical method name from C++. Here is an example from the SoAction class:

C++

void apply(soNode * node);
void apply(SoPath *path);

C:

void SoActApply(SoAction * act, SoNode * node);
void SoActApplyPath(SoAction * act, SoPath * path);

Calling Functions

You should be aware of a few differences between the way C++ calls functions and the way C does. The C++ versions of the Open Inventor methods fill in default values for some arguments. If you omit those arguments, C++ simply calls the function with the defaults. C does not fill in those defaults for you, though. You must supply values for each argument. Here's an example of a C++ call to create an appWindow object, and the equivalent C call:

C++:

Widget appWindow = SoXt::init(argv[0]);
C:
widget appWindow;
appwindow = SoXtInit(argv[0], "Inventor");

C Classes and Manual Pages

There is an online C reference manual page for every Inventor class. For detailed information on a class, see its reference manual page, which lists the functions available to that class and any data structures available. The “Inherits From” section tells you which class the current class is derived from. For many classes, this hierarchy can be several layers deep. If you want to know all the functions available to a given class, you need to know the functions available to the parent class. These are listed as part of the synopsis of the manual page. Each class has a separate include file, named after the class.

The reference manual pages also list the suggested default value for function arguments as follows:

void setSomeValue(x, y, z = 1.0)

where z = 1.0 means that 1.0 is the recommended default value for the argument z.

The reference manual pages use both the abbreviated and the unabbreviated versions of the C class names. Your programs can use both versions as well.

A Sample Open Inventor Program in C

You now know nearly enough to rewrite Example 2-4 in C. Here's one way you might do so:

main(int argc, char **argv)
{
   Widget      myWindow;
   SoSep       *root;
   SoMtl       *myMaterial;
   SoCone      *myCone;
   SoXtExamVwr *myViewer;

   myWindow = SoXtInit(argv[0], "Inventor");
   if (myWindow == NULL) exit(1);

   root = SoSepCreate();
   SoSepRef(root);
   myMaterial = SoMtlCreate();
   myCone     = SoConeCreate();
   SoMColSetR_G_B(&(myMaterial->diffuseColor), 1.0, 0.0, 0.0);
   SoSepAddChild(root, (SoNode *)myMaterial);
   SoSepAddChild(root, (SoNode *)myCone);

   /* Set up viewer: */
   myViewer = SoXtExamVwrCreateStd(myWindow, NULL);
   SoXtExamVwrSetScene(myViewer, (SoNode *)root);
   SoXtExamVwrSetTitle(myViewer, "Examiner Viewer");
   SoXtExamVwrShow(myViewer);
   SoXtShow(myWindow);
   SoXtMainLoop();
}