## `class ssgLeaf` - Leaf nodes.

Leaf nodes are those that actually make OpenGL calls or take other 'rendering' actions - they contain all of the geometric information in the scene.

    class ssgLeaf : public ssgEntity
    {
    public:
      int  getExternalPropertyIndex ()
      int  isTranslucent ()
      int       hasState ()
      ssgState *getState ()
      void      setState ( ssgState *st )

      virtual float *getVertex   ( int i )
      virtual float *getNormal   ( int i )
      virtual float *getColour   ( int i )
      virtual float *getTexCoord ( int i )

      virtual int  getNumTriangles() ;
      virtual void getTriangle ( int n, short *v1, short *v2, short *v3 )

      virtual int  getNumLines () ;
      virtual void getLine ( int n, short *v1, short *v2 ) ;

      int  getNumLines () ;
      void getLine ( int n, short *v1, short *v2 ) ;

      virtual void transform ( sgMat4 m )

      void setCullFace ( int cf )
      int  getCullFace ()

      void makeDList () ;
      void deleteDList () ;
      GLuint getDListIndex () ;
    } ;

### Pre- and Post-Draw Callbacks.

It's frequently useful to have an application function called just before and/or just after a leaf node is rendered.

      typedef int (*ssgCallback)( ssgEntity * ) ;
      ssgCallback getCallback ( int which ) ;
      void setCallback ( int which, ssgCallback cb ) ;

(Where 'which' is either SSG_CALLBACK_PREDRAW for a function that's to be called before the node is drawn or SSG_CALLBACK_POSTDRAW for one that's called after rendering.) In both cases, the function will be passed a pointer to the leaf node that's about to be drawn, and (in the case of PREDRAW callbacks), may return FALSE to prevent the node from being drawn, or TRUE to have it draw normally.

### Display Lists

A leaf node is normally rendered in 'immediate' mode in OpenGL, so that changes you make to the leaf will be reflected on the screen on the next occasion that it's drawn. However, on some graphics hardware, it's more efficient to create an OpenGL display list for each leaf node. This can be managed by calling `ssgLeaf::makeDList()`. If you want to make changes to the Leaf, you'll have to call makeDList again since OpenGL does not support the editing of display lists.

You can call `ssgLeaf::deleteDList()` to stop this leaf from being display listed from now on and to free up the display list memory. `ssgLeaf::getDListIndex()` returns the OpenGL display list handle - or zero if no display list exists for this leaf.

If you change a leaf node's geometry when it has an active display list without calling either deleteDList or makeDList again, then any subsequent operation involving rendering this node could fail.

### Face Culling.

By default, ssgLeaf nodes are back-face culled, you can change that for any given node using `ssgLeaf::setCullFace(cf)` where `cf` is TRUE to enable backface culling, FALSE to disable it. You can test the state of face culling using `ssgLeaf::getCullFace()`.

### State Management.

OpenGL supports a wide selection of state information - things like texture, materials and such. All of this information is held in a separate SSG class hierarchy: 'ssgState'. Each leaf has a state which it sets up before drawing the geometry that the leaf contains.

Nodes may also be stateless - but that isn't useful for any of the existing SSG leaf node types.

You can set the state for a node using `ssgLeaf::setState(state)` and query it using `ssgLeaf::getState()`. You can ask if a node has state information attached using `ssgLeaf::hasState()`.

Since OpenGL does not render translucent object well when Z-buffering is enabled, it's often useful to know if an object is translucent. `ssgLeaf::isTranslucent()` handles that test.

It is often useful to tag ssgState's with external properties - and you can retrieve the property of a leaf's state using `ssgLeaf::getExternalPropertyIndex()`.

### Querying Geometry

The actual storage format for geometry in classes derived from ssgLeaf varies from class to class. However, it's very useful to be able to query the geometry in an implementation-independent manner.

Although classes derived from ssgLeaf are entitled to store their geometry in any form, all of them are required to respond to queries about basic triangle primitives.

Firstly, you can get a count of the number of triangles in this leaf using `ssgLeaf::getNumTriangles()`. Each triangle has an index number for each vertex which can be queried using `ssgLeaf::getTriangle(n,&v1,&v2,&v3)` which copies the 'short' indices for the n'th triangle's three vertices into v1, v2 and v3.

Once you know the indices of a triangle's vertices, you can ask for more information about that vertex using `ssgLeaf::getVertex(i)`, `ssgLeaf::getNormal(i)`, `ssgLeaf::getColour(i)`, and `ssgLeaf::getTexCoord(i)`. These calls allow you to retrieve the i'th vertex, normal, colour or texture coordinate as a short floating point array. (3 elements for Vertex and Normal, 4 elements for Colour (RGBA) and two elements for a texture coordinate.

Analogous to getting the triangles, you may use `ssgLeaf::getNumLines ()` and `ssgLeaf::getLine ( int n, short *v1, short *v2 ) ;` to get the number of lines and to get the n. line.

You can transform all the vertices of a leaf each frame by placing an ssgTransform node above the leaf in the scene graph - but for transformations that never change, it's more efficient to pre-transform the vertices in the leaf node. `ssgLeaf::transform(matrix)` permenantly transforms all the vertices and normals of this leaf by multiplying them by the matrix. (In the case of the normals, the translation part of the matrix is ignored).

It's inadvisable to repeatedly transform a leaf using `transform` since roundoff error will be accumulated with bad consequences (eventually). In those cases, use an ssgTransform node.

## `class ssgVtxTable` - A Vertex-table leaf node.

This class allows one to represent leaf geometry as arrays of vertex, normal, texture coordinate and colour data. As a derived class of ssgLeaf, Vertex Tables add a constructor function to take the pre-computed vertex data:

      ssgVtxTable ( GLenum ty, ssgVertexArray   *vl,
                               ssgNormalArray   *nl,
                               ssgTexCoordArray *tl,
                               ssgColourArray   *cl ) ;

'ty' is an OpenGL primitive type (such as one might pass to glBegin):

        GL_POLYGON
        GL_TRIANGLE_FAN
        GL_TRIANGLES
        GL_TRIANGLE_STRIP
        GL_QUAD_STRIP
        GL_QUADS

the remaining arguments are lists of (x,y,z) vertices, (nx,ny,nz) normals, (s,t) texture coordinates and (r,g,b,a) colours.

## `class ssgVertexArray/ssgNormalArray/ssgTexCoordArray/ssgColourArray` - Vertex data storage classes.

These four classes are used for storing vertex data for ssgVtxTable nodes. Each class implements an extensible array that grows as you add data to it.

      ssg*Array::ssg*Array ( int init = 3 ) ;

When you construct the array, you may specify an initial size for it, the default is three elements. If you don't know how big the array is, don't worry about it - but if you do know, there are time and storage space advantages to telling the class the exact number.

      void ssgVertexArray  ::add ( sgVec3 data ) ;
      void ssgNormalArray  ::add ( sgVec3 data ) ;
      void ssgTexCoordArray::add ( sgVec2 data ) ;
      void ssgColourArray  ::add ( sgVec4 data ) ;

These functions tack another data element onto the end of the array.

      float *ssg*Array::get ( int i ) ;

Returns the address of the i'th element of the array.

      int ssg*Array::getNum () ;

Returns the number of data elements currently stored in the array.

      void ssg*Array::removeAll () ;

Empties the array.

## `class ssgTween` - A Vertex-table morphing node.

This node is derived from ssgVtxTable. Where VtxTable can retain a set of arrays, one each for Vertex coordinates, Normals, Texture Coordinates and Colours, the ssgTween node can store an unlimited number of 'banks' of these arrays.

Hence, one constructs an ssgTween by specifying it's OpenGL primitive type:

      ssgTween::ssgTween ( GLenum ty ) ;

And then create some number of 'banks' of data arrays by calling:

      int ssgTween::newBank ( ssgVertexArray   *vl,
                              ssgNormalArray   *nl,
                              ssgTexCoordArray *tl,
                              ssgColourArray   *cl ) ;

...once for each bank. All other ssgVtxTable calls operate ONLY on the 'current bank' - which is either the most recent one you created with newBank - or you can go back to an older bank by calling:

      void ssgTween::setBank ( int bankID ) ;
      int  ssgTween::getBank () ;

(newBank returns the number of the bank it created in case you lose count!).

ssgTween's idea of the 'current bank' is reset to zero after rendering it...so be sure to always call setBank immediately before working on it's component arrays.

When the ssgTween node is rendered, it works cooperatively with whichever ssgTweenController node is above it in the scene graph. See the section on ssgTweenController for more details.

IMPORTANT NOTE: There must be an identical number of vertices, normals, etc in each bank. If you get that wrong, SSG will exit with an 'abort'. Note that there is a specific optimisation in ssgTween that avoids the computational cost of interpolating between two sets of vertex data if EITHER:

- The ssgTweenController's selected bank number happens to be an integer.
- The previous and next banks have the same ssg*Array pointer. Since one generally doesn't wish to interpolate normals, colours or texture coordinates, it's important to pay attention to this.

<= previous = | Return to SSG Index | = next =>