Programming Concepts


View3D Components

The View3D widget library consists of three main components. The first component, the Object Library, is a library of object classes and functions, enabling the creation and modification of 3D objects. The second component, the Material Object Library, is a library of functions that allows the creation and editing of material objects. This library encapsulates all the graphic attributes of the 3D objects. The third component is the actual View3D widget, also called the Viewer. The Viewer manages and displays lists of 3D objects.

Programming with View3D requires an application to first create a View3D widget, and then create a number of 3D objects and materials. After the objects have been created, they must be added to the display list of a View3D viewer. Each 3D object must have a material object assigned when attached to a viewer. The following diagram illustrates a simple example where one viewer is used to display two objects, each having a different material.


Figure 1: Simple attachment of objects and materials to a viewer

A material can be shared by multiple objects. Also, a 3D object can be added to multiple viewers, using a different material on each viewer if desired. The following diagram illustrates a more complex case, where two objects are attached to two different viewers, the second object being displayed with a different material in the second view.


Figure 2: Complex attachment of objects and materials to multiple viewers

Function XintView3DSetMaterial is used to assign a material to an object. Function XintView3DAddObject is used to add an object to a viewer. Function XintView3DAddObjectAndMaterial combines the operations of the above functions in one call. Function XintView3DRemoveObject can be used to remove an object from the display list of a viewer, temporarily or permanently.

Each object (3D objects and material objects) keeps a link count to prevent the object from being destroyed when still in use inside a viewer. The reference count of a 3D object is set to 0 at creation time. Each time an object is added to a viewer, its reference count is incremented by 1. Conversely, it is decremented by 1 when the object is removed from a viewer. An object is destroyed when its reference count drops back to 0. Functions XintView3DRefObject and XintView3DUnRefObject can be used to increase or decrease the reference count of an object respectively. The reference count of a material object is increased by 1 when assigned to a 3D object, it is decreased by 1 when the object is destroyed or when a new material is assigned to the object.


OpenGL

The View3D widget uses the OpenGL library for the underlying drawing layer, which enables it to take advantage of accelerated graphics on all platforms supporting OpenGL. The View3D widget can also interface with the public domain library Mesa 3-D, an implementation of the OpenGL library under the X environment.

Because View3D is based on OpenGL, it may require a special visual to create its window, which can be different from the visual used by the application. View3D usually creates this special visual (one that is compatible with OpenGL) at creation time, along with a matching colormap. This operation is transparent for the application.

When linking with a native OpenGL library, the selected visual will, in most cases, be a TrueColor visual.

When linking with the Mesa 3-D library, the selected visual will, in most cases, be a PseudoColor visual. In the case of an 8-bit PseudoColor visual, the Mesa library tries to allocate a color cube containing 225 colors. If this allocation fails for some colors, the closest color available in the colormap will be used. In the case of a 24-plane screen, an 8-bit visual is selected if available. It is possible to override the visual selection process using environment variable MESA_RGB_VISUAL. For example, the following setting ( specified using the csh syntax) forces the Mesa library to select a 24-bit visual:

     setenv MESA_RGB_VISUAL "TrueColor 24"

Possible specifications for the visual type include TrueColor, PseudoColor, StaticColor, GrayScale and DirectColor. What you specify must match a valid visual otherwise the directive will be ignored.

Applications requiring full control over the visual and colormap selection process can use View3D resource XmNvisual and Core resource XmNcolormap to impose a particular visual and colormap. Convenience functions XintGlChooseVisual and XintGlGetVisualInfo can be used to facilitate this process.


Data Types

The elementary data type for the View3D widget is defined as XintReal. By default this type is defined as:

     typedef float XintReal; /* default type */

For applications requiring more precision, a special version of the library can be provided where type XintReal is defined as:

     typedef double XintReal; /* ONLY when USE_DOUBLE is set */

Note: It is not enough to set flag USE_DOUBLE when you compile your application. You must build or obtain a special version of the View3D library compiled with flag USE_DOUBLE set.


Colors

Colors for 3D objects are specified using a data structure of type XintColor4 which is described below:

     typedef float XintColor4[4];

This data type contains 4 values, all between 0.0 and 1.0, which represent the red, green, blue and transparency values respectively. A set of convenience functions described in Color Functions section is available for converting pixel values to XintColor4 values and vice versa.


Memory Allocation

All functions requiring arrays of data as arguments make a copy of those arrays internally. So, the application is responsible for freeing its copies of the data after it is no longer needed.

The following code sample shows when to allocate and free the data required to create a line object.

    XintVector3  *vertices;
    ...
    /* Generate line points */
    vertices = (XintVector3 *) XtMalloc(sizeof(XintVector3) * NV);

    for (i=0; i<NV; i++) {
         vertices[i][0] = sin((double) i/10.);
         vertices[i][1] = cos((double) i/10.);
         vertices[i][2] = cos((double) i/7.);
    }

    /* Create line object */
    line = XintView3DCreateLine("line", XintOBJECT_LINE_POLYLINE, 2.0,
                                NV, vertices, 0, NULL, True, NULL, NULL);
      
    /* Free the line points */
    XtFree((char *) vertices);
    ...


Vertex Specifications

View3D uses an indexed scheme for referencing vertices. When defining most objects, a list of vertices is supplied along with a list of indices that define the object's shape. The following example illustrates the method for specifying the vertices for a Mesh Surface object of type XintOBJECT_MESH_SURFACE_POLYS.


             num_verts = 10; /* Number of vertices */
                             
             num_lists = 3; /* Number of polygons */
                             
             num_indices[0] = 5; /* Num indices in poly 0 */
             num_indices[1] = 4; /* Num indices in poly 1 */
             num_indices[2] = 6; /* Num indices in poly 2 */
                             
             indices[0][0] = 0; /* Poly 0 Index 0 -> Vert 0 */
             indices[0][1] = 1; /* Poly 0 Index 1 -> Vert 1 */
             indices[0][2] = 2; /* Poly 0 Index 2 -> Vert 2 */
             indices[0][3] = 8; /* Poly 0 Index 3 -> Vert 8 */
             indices[0][4] = 7; /* Poly 0 Index 4 -> Vert 7 */
             indices[1][0] = 6; /* Poly 1 Index 0 -> Vert 6 */
             indices[1][1] = 7; /* Poly 1 Index 1 -> Vert 7 */
             indices[1][2] = 8; /* Poly 1 Index 2 -> Vert 8 */
             indices[1][3] = 5; /* Poly 1 Index 3 -> Vert 5 */
             indices[2][0] = 8; /* Poly 2 Index 0 -> Vert 8 */
             indices[2][1] = 2; /* Poly 2 Index 1 -> Vert 2 */
             indices[2][2] = 3; /* Poly 2 Index 2 -> Vert 3 */
             indices[2][3] = 4; /* Poly 2 Index 3 -> Vert 4 */
             indices[2][4] = 9; /* Poly 2 Index 4 -> Vert 9 */
             indices[2][5] = 5; /* Poly 2 Index 5 -> Vert 5 */

Figure 3: Indexed Vertices (Mesh Surface - Polygon)


This example shows how to use the indices for most other data types.


             num_verts = 5; /* Number of vertices */
 
             num_lists = 1; /* Only 1 list */
 
             num_indices[0] = 5; /* Num indices in poly 0 */
 
             indices[0][0] = 0; /* Tri 0 Index 0 -> Vert 0 */
             indices[0][1] = 1; /* Tri 0 Index 1 -> Vert 1 */
             indices[0][2] = 4; /* Tri 0 Index 2 -> Vert 4 */
             indices[0][3] = 1; /* Tri 0 Index 0 -> Vert 1 */
             indices[0][4] = 3; /* Tri 0 Index 1 -> Vert 3 */
             indices[0][5] = 4; /* Tri 0 Index 2 -> Vert 4 */
             indices[0][6] = 2; /* Tri 0 Index 0 -> Vert 2 */
             indices[0][7] = 3; /* Tri 0 Index 1 -> Vert 3 */
             indices[0][8] = 1; /* Tri 0 Index 2 -> Vert 1 */

             Only use 1 list. Every 3 indices is 1 triangle. 
             This method works for most of the data types that 
             use more than one list of indices.

Figure 4: Indexed Vertices