Data Structures

The following sections provide details on the data structures used in realtime shader development:

• Constants and Enums

• Data Types

• System Parameters

• Property Page Parameters

• Geometry Data

Constants and Enums

The following constants and enums are used in the Realtime Shader API version 2.0:

• Versioning

• Application IDs

• Shader flags

• Object flags

• Light types

• Camera types

• Requirements

• Triangle list types

Versioning

    #define XSI_RTSHADER_VERSION 200 //! Realtime shader protocol version 2.00

Application IDs

    #define APPID_XSI     0x00000000 //! XSI
    #define APPID_XSI_OGL 0x00000001 //! XSI running in OpenGL (always the case)
    #define APPID_XSIVIEWER 0x00000100 //! XSIViewer
    #define APPID_XSIVIEWER_OGL 0x00000101 //! XSIViewer running the OpenGL driver
    #define APPID_XSIVIEWER_D3D 0x00000102 //! XSIViewer running the DirectX driver
    #define APPID_XSIVIEWER_XBOX 0x00000103 //! XSIViewer running on XBOX
    #define APPID_XSIVIEWER_PS2GL 0x00000104 //! XSIViewer running on PS2 GL (not supported)

Shader flags

    #define RTS_SHADER_FLAG_NONE 0x00000000 //! no flag
    #define RTS_SHADER_FLAG_PARAM_CHANGE 0x00000001 //! parameter changed
    #define RTS_SHADER_FLAG_FIRST 0x00000002   //! shader is the first to be executed for this material
    #define RTS_SHADER_FLAG_LAST 0x00000004 //! shader is the last to be executed for this material
    #define RTS_SHADER_FLAG_TREE_CHANGE 0x00000008 //! shader tree has physically changed

Object flags

    #define RTS_OBJECT_FLAG_NONE 0x00000000 //! no flag
    #define RTS_OBJECT_FLAG_TOPO 0x00000001 //! topological change occured
    #define RTS_OBJECT_FLAG_DEFORM 0x00000002 //! deform occured

Light types

    enum eXSI_RTS_LightType
    {
       RTS_LIGHT_POINT, //! A point light
       RTS_LIGHT_INFINITE, //! An infinite (or parallel) light
       RTS_LIGHT_SPOT //! A spot light
    };

Camera types

    enum eXSI_RTS_CameraType
    {
       RTS_ORTHOGRAPHIC, //! Orthographic
       RTS_PERSPECTIVE //! Perspective
    };

Requirements

    enum eXSI_RTS_RequirementType
    {
       RTS_REQUIRE_ZSORT =   0,        // The shader requires the object to be sorted
       RTS_REQUIRE_RESERVED = 1,      // Obsolete and no longer supported
       RTS_REQUIRE_OBJECTHANDLE = 2, // The shader requires the object handle
       RTS_REQUIRE_MATERIALHANDLE = 3, // The shader requires the material handle
       RTS_REQUIRE_LIGHTHANDLE = 4,   // The shader requires the light handle
       RTS_REQUIRE_PRIMARYINITUIGUID = 5, // GUID of the parameter that will trigger a call to InitUI
       RTS_REQUIRE_SECONDARYINITUIGUID = 6, // GUID of the parameter that will trigger a call to _InitUI
       RTS_REQUIRE_UNUSED =   0xffffffff // Unused
    };

Triangle list types

    enum eXSI_RTS_TriangleListType
    {
       RTS_TL_SINGLE_INDEX_ARRAY, //! arrays define positions, normals, UV and colors and a single index is used
       RTS_TL_BYREF,         //! positions, normals, UVs and colors are accessed by pointers, everything is in float
       RTS_TL_BYREF_POSD     //! positions, normals, UVs and colors are accessed by pointers, everything is in float, except position which is double
    };

Data Types

The following data types are used in the Realtime Shader API version 2.0:

• 2D Vector

• 3D Vector

• Double precision 3D Vector

• 4D Vector

• RGB color

• Normalized RGBA color

• RGBA color

• ARGB color

• Image data

2D Vector

    typedef struct tagXSI_RTS_Vector2
    {
       float m_x;                                //! The X component
       float m_y;                                //! The Y component
    } XSI_RTS_Vector2;

3D Vector

    typedef struct tagXSI_RTS_Vector3d
    {
       double m_x;                               //! The X component
       double m_y;                               //! The Y component
       double m_z;                               //! The Z component
    } XSI_RTS_Vector3d;

Double precision 3D Vector

    typedef struct tagXSI_RTS_Vector3
    {
       float m_x;                                //! The X component
       float m_y;                                //! The Y component
       float m_z;                                //! The Z component
    } XSI_RTS_Vector3;

4D Vector

    typedef struct tagXSI_RTS_Vector4
    {
       float m_x;                                //! The X component
       float m_y;                                //! The Y component
       float m_z;                                //! The Z component
       float m_w;                                //! The W component
    } XSI_RTS_Vector4;

RGB color

    typedef struct tagXSI_RTS_ColorRGB
    {
       unsigned char m_red;                      //! The red component
       unsigned char m_green;                    //! The green component
       unsigned char m_blue;                 //! The blue component
    } XSI_RTS_ColorRGB;

Normalized RGB color

    typedef struct tagXSI_RTS_ColorRGBf
    {
       float      m_red;                       //! The red component
       float      m_green;                     //! The green component
       float      m_blue;                      //! The blue component
    } XSI_RTS_ColorRGBf;

RGBA color

    typedef struct tagXSI_RTS_ColorRGBA
    {
       unsigned char m_red;                      //! The red component
       unsigned char m_green;                    //! The green component
       unsigned char m_blue;                 //! The blue component
       unsigned char m_alpha;                    //! The alpha component
    } XSI_RTS_ColorRGBA;

Normalized RGBA color

    typedef struct tagXSI_RTS_ColorRGBAf
    {
       float m_red; //! The red component
       float m_green; //! The green component
       float m_blue; //! The blue component
       float m_alpha; //! The alpha component
    } XSI_RTS_ColorRGBAf;

ARGB color

    typedef struct tagXSI_RTS_ColorARGB
    {
       unsigned char m_alpha;                    //! The alpha component
       unsigned char m_red;                      //! The red component
       unsigned char m_green;                    //! The green component
       unsigned char m_blue;                 //! The blue component
    } XSI_RTS_ColorARGB;

Image data

    typedef struct tagXSI_RTS_Texture
    {
       char   *m_pchPath;                       //! The path of the image for this texture
       ULONG  m_lWidth;                         //! The width of the image
       ULONG  m_lHeight;                        //! The height of the image
       ULONG  m_lNbChannels;                //! The number of channels
       ULONG  m_lPixelType;                     //! The type of pixel
       ULONG  m_lBufferSize;                //! The size of the pixel buffer
       unsigned char *m_pBuffer;                 //! The pixel buffer
       ULONG  m_lDirty;                         //! The texture is dirty and should be refreshed
    } XSI_RTS_Texture;

System Parameters

System parameters are passed to all shader’s callbacks The system parameters consist of the following structure:

    typedef struct tagXSI_RTS_SystemParams
    {
       ULONG         m_lNbParams;          //! Number of parameters

       ULONG         m_lAppID;             //! Application ID
       ULONG         m_lRTSVersion;    //! Realtime shader protocol version
       ULONG         m_lContext;           //! Context

       void          *m_pShaderHandle;     //! Shader instance handle (CRef)
       void          *m_pObjectHandle;     //! Owner object handle (CRef)
       void          *m_pMaterialHandle;   //! Owner material handle (CRef)

       void          *m_pGS;           //! Handle to the graphic system (CRef)
       XGSExtensionsGL *m_pGLExt;           //! XSI OpenGL extension wrapper flags
       XGSGLExtensionsFuncs *m_pGLExtFuncs; //! XSI OpenGL extension wrapper functions

       ULONG         m_lShaderFlags;       //! Shader flags
       ULONG         m_lObjectFlags;       //! Object flags

       float         m_m4x4ObjectPose[16]; //! Object's transformation matrix

       XSI_RTS_SceneData *m_SceneData;      //! Scene Data
    } XSI_RTS_SystemParams;

The application ID [m_lAppID] can have the following values:

• APPID_XSI
The host application is SOFTIMAGE|XSI

• APPID_XSI_OGL
The host application is SOFTIMAGE|XSI and is running in OpenGL mode (Always)

• APPID_XSIVIEWER
The host application is the SOFTIMAGE|XSI Viewer

• APPID_XSIVIEWER_OGL
The host application is the SOFTIMAGE|XSI Viewer and is running with the OpenGL driver

• APPID_XSIVIEWER_D3D
The host application is the SOFTIMAGE|XSI Viewer and is running with the DirectX driver

• APPID_XSIVIEWER_XBOX
The host application is the SOFTIMAGE|XSI Viewer and is running on the XBOX

• APPID_XSIVIEWER_PS2GL
The host application is the SOFTIMAGE|XSI Viewer and is running on the PS2

The realtime shader protocol version [m_lRTSVersion] should be 200 for this version of the Realtime Shader API (2.0).

m_lContext uniquely identifies the viewport during an XSI session. Each viewport (regular or object view) has an XGS context associated with it. m_lContext is a pointer to the context object cast to a LONG.

The shader handle [m_pShaderHandle] is a CRef handle to the shader, you can use the SOFTIMAGE|XSI C++ API to access it.

The object handle [m_pObjectHandle] is a CRef handle to the object that is using the material where the shader is connected. You can use the SOFTIMAGE|XSI C++ API to access it. This is valid only if the shader sets its requirement for RTS_REQUIRE_OBJECTHANDLE to TRUE.

The material handle [m_pMaterialHandle] is a CRef handle to the material that is connected to this shader. You can use the SOFTIMAGE|XSI C++ API to access it. This is valid only if the shader sets its requirement for RTS_REQUIRE_MATERIALHANDLE to TRUE. When used in a XGS override material, this is the handle to the original material and not the override material.

The handle for the graphic system [m_pGS] can be used as a XSI::CGraphicSequencer object with SOFTIMAGE|XSI C++ API.

The OpenGL extension wrapper flags [m_pGLExt] indicate whether a particular OpenGL extension is used. Simply test the appropriate field in that structure. For example, if you want to test whether your hardware supports the GL_ARB_multitexture extension, then simply check if m_pGS->_GL_ARB_multitexture is set to TRUE.

The OpenGL extension wrapper functions [m_pGLExtFuncs] can be called directly from that structure. For example, if you want to call the glClientActiveTextureARB extension function, just use m_pGLExtFuncs->glClientActiveTextureARB.

The shader flag [m_lShaderFlags] can have one or more of the following values:

• RTS_SHADER_FLAG_NONE
Nothing interesting happened since the last refresh.

• RTS_SHADER_FLAG_PARAM_CHANGE
A parameter of the shader has changed.

• RTS_SHADER_FLAG_FIRST
Not implemented. The shader is the first node in the shader tree (the first node executed).

• RTS_SHADER_FLAG_LAST
Not implemented. The shader is the last node in the shader tree (the last shader executed).

• RTS_SHADER_FLAG_TREE_CHANGE
The topology of the shader tree on the owner material has changed since the last refresh. For example, a node was connected or disconnected.

The object flag [m_lObjectFlags]can have one or mode of the following values:

• RTS_OBJECT_FLAG_NONE
Nothing interesting happened since the last refresh.

• RTS_OBJECT_FLAG_TOPO
The object’s topology has changed since the last refresh.

• RTS_OBJECT_FLAG_DEFORM
The object was deformed but it’s topology is the same since the last refresh.

The object pose [m_m4x4ObjectPose] is a 4x4 matrix containing the global transformation of the object.

The scene data [m_SceneData] is a structure that contains camera and light information. The structure is as follows:

    typedef struct tagXSI_RTS_SceneData
    {
       int               m_iNbLights;           //! Number of lights
       XSI_RTS_Light* m_pLights;             //! Array of XSI_RTS_Light structures

       XSI_RTS_Camera m_sCamera;             //! The current camera

       double            m_fCurrentTime;        //! Current time
    } XSI_RTS_SceneData;

Each light has the following structure:

    typedef struct tagXSI_RTS_Light
    {
       float             m_fRed;            //! Light red value
       float             m_fGreen;              //! Light green value
       float             m_fBlue;               //! Light blue value
       float             m_fAlpha;              //! Light alpha value

       float             m_fPosX;               //! Light X position
       float             m_fPosY;               //! Light Y position
       float             m_fPosZ;               //! Light Z position
       float             m_fPosW;               //! Light W position

       float             m_fDirX;               //! Light X direction
       float             m_fDirY;               //! Light Y direction
       float             m_fDirZ;               //! Light Z direction

       float             m_fConeAngle;          //! Spot light cone angle

       int               m_iID;                 //! OpenGL light ID
       char*             m_pchID;               //! Light handle

       eXSI_RTS_LightType m_eType;               //! Light type

       bool              m_bCastsShadows;       //! Light casts shadows

       bool              m_bVisible;            //! Light object is visible

    } XSI_RTS_Light;

The camera has the following structure:

    typedef struct tagXSI_RTS_Camera
    {
       float             m_mMatrix[16];     //! The camera matrix
       eXSI_RTS_CameraType m_eCameraType;    //! The type of camera (ortho, perspective)

       float             m_fRight;              //! Frustum right
       float             m_fLeft;               //! Frustum left
       float             m_fTop;            //! Frustum top
       float             m_fBottom;             //! Frustum bottom

       float             m_fNear;               //! Near plane
       float             m_fFar;            //! Far plane

       float             m_fFOV;            //! Field of view

       float             m_fAspect;             //! Aspect ratio
    } XSI_RTS_Camera;

Property Page Parameters

The parameters of the property page are stored in an array of 32 bit integers. This array can be cast to a more meaningful structure that can be accessed easily in the shader code. For example, if I had a property page with the following definition:

       Parameter "inner_ring" input
       {
           title = "";
           guid = "{DCA7EB86-AF1C-45F8-929B-FD2DB7F70158}";
           type = scalar;
           flags = 0;
           texturable = off;
           value = 1;
           writable = on;
           animatable = on;
           persistable = on;
           readable = on;
           inspectable = on;
       }
       Parameter "outer_ring" input
       {
           title = "";
           guid = "{2B8CEDE8-14A8-4C63-85D7-1422156C87CB}";
           type = scalar;
           flags = 0;
           texturable = off;
           value = 1.1;
           writable = on;
           animatable = on;
           persistable = on;
           readable = on;
           inspectable = on;
       }
       Parameter "color" input
       {
           title = "";
           guid = "{F9F136DB-4C67-4CB6-8CAF-5FDE63074920}";
           type = color;
           flags = 0;
           texturable = off;
           value = 1.0 0.0 0.0 0.5;
           writable = on;
           animatable = on;
           persistable = on;
           readable = on;
           inspectable = on;
       }

Then you can create a structure as follows:

    typedef struct tagMyStruct
    {
       float         inner_ring;
       float         outer_ring;
       XSI_RTS_ColorRGBAf color;
    } MyStruct;

| XSI packs the parameters in exactly the same order as they are defined in the SPDL with the exception of texture parameters, which are always written at the end of the struct.

And in the code itself, it is just a simple matter of casting the property page void pointer to the structure.

    MyStruct *l_pPPG = (MyStruct *) in_pParams;

Supporting 64-bit Platforms

To to support 64-bit platforms, realtime shaders must use the #pragma pack directive to remove padding between structure fields:

    #pragma pack(push, 1)
    // PPG structures...
    #pragma pack(pop)

On 64-bit platforms, all structures used to construct a property page must be compiled without padding between the structure fields. This is because pointers to PPG structures are initialized by type-casting a void pointer:

    MyPPG * my_ppg = (MyPPG*) in_pVoid;

The #pragma pack directive is not necessary on 32-bit platforms, because on 32-bit platforms a PPG contains only floats (4 bytes), longs (4 bytes), and pointers (4 bytes), and therefore the structures never contain padding. But on 64-bit platoforms, where pointers are 8 bytes, if you don't force the compiler to remove the automatic padding, the struct may contain padding. This padding is not considered when initializing the void pointer (in_pVoid). Therefore, the direct type casting would not work.

Mapping SPDL parameters to C++

Here is a table of mapping for SPDL parameters.

SPDL type | C++ type | Number of bytes (32-bit platforms) | Number of bytes (64-bit platforms)
Boolean | LONG | 4 | 4
Color | XSI_RTS_ColorRGBAf | 16 | 16
Filename | unsigned char * | 4 | 8
Integer | LONG | 4 | 4
Matrix | float[16] | 64 | 64
Scalar | float | 4 | 4
String | unsigned char * | 4 | 8
Texture | XSI_RTS_Texture | 32 | 40
Texture space | LONG | 4 | 4
Vector | float[4] | 16 | 16

Geometry Data

The geometry data contains both the vertices and their attributes, and the triangle information. The shader only receives the triangles that are using it. If for example, a shader is set on a partial cluster, then it will only receive the triangles that are on that cluster. To get the complete topology of the object, use the object handle and the SOFTIMAGE|XSI C++ sdk to extract it.

The geometry data is stored in the following structure:

    typedef struct tagXSI_RTS_TriangulatedGeometry
    {
       // Triangle lists information
       ULONG         m_Type;
       ULONG         m_lNbTriangleLists; //! Number of triangle lists
       XSI_RTS_TriangleList *m_pTriangleLists; //! Triangle lists
       ULONG         m_NbVertices;  //! Total number of vertices
       // Pointer streams
       XSI_RTS_Vector3d **m_pPositionDPtrArray; //! Array of pointers to the positions (DOUBLE)
       XSI_RTS_Vector3 **m_pPositionPtrArray; //! Array of pointers to the positions
       XSI_RTS_Vector3 **m_pNormalPtrArray; //! Array of pointers to the normals
       XSI_RTS_ColorRGBA **m_pColorPtrArray; //! Array of pointers to the colors
       XSI_RTS_Vector2 **m_pTexCoordPtrArray; //! Array of pointers to the texture

       // Vertex attribute arrays streams
       ULONG         m_NbUniqueVertices; //! Total number of unique vertices
       XSI_RTS_Vector3 *m_pPositionArray; //! Array of positions
       XSI_RTS_Vector3 *m_pNormalArray; //! Array of normals (interleaved by streams)
       XSI_RTS_ColorRGBA *m_pColorArray; //! Array of colors (interleaved by streams)

       XSI_RTS_Vector2 *m_pTexCoordArray; //! Array of texture coordinates
       ULONG         *m_pIndices;   //! Array of global indices

       // Number of normals, colors and texture coordinates
       ULONG         m_lNbNormalStreams; //! Number of normal streams
       ULONG         m_lNbColorStreams; //! Number of color streams
       ULONG         m_lNbTexCoordStreams; //! Number of texture coordinates streams

    } XSI_RTS_TriangulatedGeometry;

This section contains the following topics:

• Geometry Information

• Triangle List Information

• Vertex Attribute Information

• Multi-indexed Vertex Data

• Single Indexed Vertex Data

Geometry Information

The geometry type [m_Type] can be:

• RTS_TL_SINGLE_INDEX_ARRAY
The single indexed vertex data is used. The triangle’s vertices use the same index in all the vertex arrays. The triangle connection information is stored in the m_pIndices array.

• RTS_TL_BYREF
The multi indexed vertex data is used. The triangle’s vertices don’t use the same index in all the vertex arrays. The position data is stored as a float value therefore, the m_pPositionPtrArray is used and the m_pPositionDPtrArray is ignored. The triangle connection information is stored in the vertex data arrays. To access the vertex data you need to dereference it twice.

• RTS_TL_BYREF_POSD
The multi indexed vertex data is used. The triangle’s vertices don’t use the same index in all the vertex arrays. The position data is stored as a double value therefore, the m_pPositionDPtrArray is used and the m_pPositionPtrArray is ignored. The triangle connection information is stored in the vertex data arrays. To access the vertex data you need to dereference it twice.

Triangle List Information

Triangles are packed into lists. Each list can either be a single triangle strip, or a list of unconnected triangles.

The number of triangle lists [m_lNbTriangleLists] indicates how many lists are going to be passed to the realtime shader. This includes triangle strips and triangle lists.

The triangle list array [m_pTriangleLists] contains the triangles lists themselves. A triangle list has the following structure.

    typedef struct tagXSI_RTS_TriangleList
    {
       ULONG         m_lOffset;            //! Starting offset of that triangle list
       ULONG         m_lNbVertices;    //! Number of vertices for that triangle list
       ULONG         m_lType;              //! Type of triangle list (strip, list, fan : Mapped with OGL constants)
       ULONG         m_lMinIndex;          //! Minimum index used for this triangle list
       ULONG         m_lMaxIndex;          //! Maximum index used for this triangle list
       ULONG         m_lReserved[4];       //! Reserved
                                               } XSI_RTS_TriangleList;

The triangle list offset [m_lOffset] indicate where this triangle list starts in the vertex data arrays.

The number of vertices used for this list of triangles is specified by [m_lNbVertices]

The type of triangle list [m_lType]can be:

• GL_TRIANGLES
Each vertex of the triangles is stored in the vertex data arrays, the layout is as follows:

Triangle 0 | Vertex 0 Vertex 1 Vertex 2
Triangle 1 | Vertex 3 Vertex 4 Vertex 5
Triangle 2 | Vertex 6 Vertex 7 Vertex 8
… |
Triangle n | Vertex (n*3) Vertex (n*3) + 1 Vertex (n*3) + 2

• GL_TRIANGLE_STRIP
The first two vertices of a triangle are the last two vertices of the previous triangle in the list, except for the first triangle which is complete. The layout is as follows:

Triangle 0 | Vertex 0 Vertex 1 Vertex 2
Triangle 1 | Vertex 3
Triangle 2 | Vertex 4
… |
Triangle n | Vertex n+2

In this case, triangle 0 uses vertices 0, 1, 2, triangle 1 uses vertices 1, 2, 3, triangle 2 uses vertices 2, 3, 4 and so on.

The minimum index and maximum index [m_lMinIndex, m_lMaxIndex] are used to define the range of vertices a triangle list uses when the geometry type is RTS_TL_SINGLE_INDEX_ARRAY

Vertex Attribute Information

The vertex attribute information indicates how many of the following attributes are stored on the vertex:

• Normals [m_lNbNormalStreams]

• Colors [m_lNbColorStreams]

• Texture coordinates [m_lNbTexCoordStreams]

Each set of attribute is interleaved in the corresponding vertex data array. For example, if the object has 2 texture coordinates and 3 colors, then the vertex array would be as follows:

Triangle 0 | Vertex 0 | Color 0, set 0 | Texture Coordinate 0, set 0
|  | Color 0, set 1 | Texture Coordinate 0, set 1
|  | Color 0, set 2 |
| Vertex 1 | Color 1, set 0 | Texture Coordinate 1, set 0
|  | Color 1, set 1 | Texture Coordinate 1, set 1
|  | Color 1, set 2 |
| Vertex 2 | Color 2, set 0 | Texture Coordinate 2, set 0
|  | Color 2, set 1 | Texture Coordinate 2, set 1
|  | Color 2, set 2 |

Multi-indexed Vertex Data

This vertex data is used when the geometry type is RTS_TL_BYREF or RTS_TL_BYREF_POSD. With this data layout, the triangle data is stored directly in the vertex data arrays. If the geometry type is RTS_TL_BYREF, then the position of the vertices is stored in m_pPositionPtrArray. If the geometry type is RTS_TL_BYREF_POSD, the position of the vertices is stored in m_pPositionDPtrArray.

The total number of vertices is specified by [m_NbVertices]. This is the total number of all vertices used by all triangles in the geometry.

To extract the position x,y,z of a vertex [m_pPositionDPtrArray] or [m_pPositionDPtrArray], use:

    XSI_RTS_Vector3 *position = m_pPositionPtrArray[ index ];

To extract the normal x,y,z of a vertex [m_pNormalPtrArray], use:

    XSI_RTS_Vector3 *normal = m_pNormalPtrArray[ index ] [ normal_stream_index ];

To extract the color RGBA of a vertex [m_pColorPtrArray], use:

    XSI_RTS_ColorRGBA *color = m_pColorPtrArray[ index ] [ color_stream_index ];

To extract the texture coordinates of a vertex [m_pTexCoordPtrArray], use:

    XSI_RTS_Vector2 *texcoord = m_pTexCoordPtrArray[ index ] [ texture_coordinate_stream_index ];

Single Indexed Vertex Data

This vertex data is used when the geometry type is RTS_TL_SINGLE_INDEX_ARRAY. With this data layout, the triangle data is stored in m_pIndices array.

The total number of vertices is specified by [m_NbVertices]. This is the total number of all vertices used by all triangles in the geometry. The size of the vertex data arrays is specified by [m_NbUniqueVertices].

To extract the position x,y,z of a vertex [m_pPositionArray], use:

    m_pPositionArray [m_pIndices [index]]

To extract the normal x,y,z of a vertex [m_pNormalArray], use:

    m_pNormalArray[m_pIndices [index]][ normal_stream_index ]

To extract the color RGBA of a vertex [m_pColorArray], use:

    m_pColorArray[m_pIndices [index]][ color_stream_index ]

To extract the texture coordinates of a vertex [m_pTexCoordArray], use:

    m_pTexCoordArray[m_pIndices [index]][ texture_coordinate_stream_index ]

Additionally for OpenGL this structure makes it very easy to use the glDrawElements calls:

       // Set the position array
       glEnableClientState( GL_VERTEX_ARRAY );
       glVertexPointer
       (
           3,
           GL_FLOAT,
           0,
           tmpGeom.m_pPositionArray
       );

       glDisableClientState( GL_COLOR_ARRAY );
       glDisableClientState( GL_TEXTURE_COORD_ARRAY );

       // Set the normal array
       if(tmpGeom.m_pNormalArray && in_bNormals)
       {
           glEnableClientState( GL_NORMAL_ARRAY );
           glNormalPointer
           (
              GL_FLOAT,
              0,
              tmpGeom.m_pNormalArray
           );
       }

       // Colors
       if(tmpGeom.m_pColorArray && in_bColors)
       {
           if ( !pGLExt->_GL_EXT_secondary_color || tmpGeom.m_lNbColorStreams < 2)
           {
              glEnableClientState( GL_COLOR_ARRAY );
              glColorPointer
                  (
                  4,
                  GL_UNSIGNED_BYTE,
                  0,
                  tmpGeom.m_pColorArray
                  );
           } else {
              glEnableClientState( GL_COLOR_ARRAY );
              glColorPointer
                  (
                  4,
                  GL_UNSIGNED_BYTE,
                  0,
                  tmpGeom.m_pColorArray
                  );

              glEnable ( GL_COLOR_SUM );
              pGLExtFuncs->glSecondaryColorPointerEXT(
                  3,
                  GL_UNSIGNED_BYTE,
                  0,
                  tmpGeom.m_pColorArray
                  );

           }
       }

       // Set the texture coordinates
       for(loop = 0; loop < nbUVs; loop++)
       {
           if(tmpGeom.m_pTexCoordArray && in_bUVs)
           {
              glEnableClientState( GL_TEXTURE_COORD_ARRAY );

              if(pGLExt->_GL_ARB_multitexture)
              {
                  pGLExtFuncs->glClientActiveTextureARB(in_pTexCoordMap->target[loop]);
              }

              glTexCoordPointer
              (
                  2,
                  GL_FLOAT,
                  (nbUVs - 1) * sizeof(XSI_RTS_Vector2),
                  tmpGeom.m_pTexCoordArray + in_pTexCoordMap->UVSet[loop]
              );
           }
       }

       // Draw triangles
       for(i = 0; i < tmpGeom.m_lNbTriangleLists ; i++)
       {
           if(pGLExtFuncs->glDrawRangeElementsEXT)
           {
              pGLExtFuncs->glDrawRangeElementsEXT
              (
                  tmpGeom.m_pTriangleLists[i].m_lType,
                  tmpGeom.m_pTriangleLists[i].m_lMinIndex,
                  tmpGeom.m_pTriangleLists[i].m_lMaxIndex,
                  tmpGeom.m_pTriangleLists[i].m_lNbVertices,
                  GL_UNSIGNED_INT,
                  tmpGeom.m_pIndices + tmpGeom.m_pTriangleLists[i].m_lOffset
              );
           }
           else
           {
              glDrawElements(tmpGeom.m_pTriangleLists[i].m_lType, tmpGeom.m_pTriangleLists[i].m_lNbVertices,
    GL_UNSIGNED_INT, tmpGeom.m_pIndices + tmpGeom.m_pTriangleLists[i].m_lOffset);
           }
       }