A Simple Scene Graph API for OpenGL.

## `class ssgState` - OpenGL state representation.

Each leaf node will have some kind of ssgState node associated with it that contains all relevent OpenGL state information.

There can (in principal) be a number of different ways to represent OpenGL state - but all must be derived from an ssgState:

      class ssgState : public ssgBase
      {
        int  getExternalPropertyIndex () ;
        void setExternalPropertyIndex ( int i ) ;

        ssgStateCallback getStateCallback ( int cb_type ) ;
        void setStateCallback ( int cb_type, ssgStateCallback cb ) ;

        virtual void force () ;
        virtual void apply () ;
      } ;

### Callbacks.

States are 'applied' immediately before the geometry they are attached to is rendered. Applying the state causes all of it's properties to be set up in OpenGL.

Each state has three optional callback function hooks. The application program can have a function called before the state is applied, after it is applied (but before the geometry is drawn) and another after the geometry is rendered - immediately before the next state is applied.

You can set those three callbacks with setStateCallback - passing either SSG_CALLBACK_PREAPPLY, SSG_CALLBACK_PREDRAW or SSG_CALLBACK_POSTDRAW as the first parameter and the address of your function as the second.

### External Properties.

Each state entity can have an external property - which is a simple integer that can be set using `ssgState::setExternalPropertyIndex(i)` or queried using `ssgState::getExternalPropertyIndex()`. External properties are of use to certain sorts of applications programs, for example, a game might want to encode the set of OpenGL state information that represents Lava as something that is hot and Ice as something that is cold by encoding the temperature of the material in the External property field. Most applications will probably use this field as an index into a table of material properties inside the application itself.

### Applying a State.

Whilst it's rare for an application to need to deal with an ssgState once it has been defined, there may be occasions when the application wishes to draw objects of it's own without using SSG's scene graph. This often is the case with on-screeen symbology.

In such cases, it is important to bear in mind that SSG changes the OpenGL state as little as possible - in order to save time. Hence, when a leaf node has just been drawn with one set of state information, and another leaf node is about to be drawn using another, SSG carefully compares the two states to see how they differ and arranges to make only the fewest possible OpenGL state change calls. If the application goes in "behind SSG's back" and changes state then SSG will be confused.

There are two ways to achive this. One is to use SSG state classes to change the state by calling `ssgState::apply()`. That call will ensure that OpenGL's state matches the desired state using the minimum of calls. However, if your application absolutely MUST make it's own state calls then you should call `ssgState::force()` to force all aspects of a specified state to be set in OpenGL so that SSG can be certain about how things are set up.

## `class ssgSimpleState` - Simple State class.

ssgSimpleState is currently the only concrete class derived from ssgState. It has so far proved adequate for all state management.

      class ssgSimpleState : ssgState
      {
        void disable ( GLenum mode ) ;
        void enable  ( GLenum mode ) ;
        void set ( GLenum mode, int val ) { val ? enable(mode) : disable(mode) ; }

        void setTexture ( char *fname, int wrapu = TRUE, int wrapv = TRUE )
        void setTexture ( ssgTexture *tex )
        void setTexture ( GLuint tex )
        void setColourMaterial ( GLenum which )
        void setMaterial ( GLenum which, float r, float g, float b, float a = 1.0f )
        void setMaterial   ( GLenum which, sgVec4 rgba )
        void setShininess ( float sh )
        void setShadeModel ( GLenum model )
        void setAlphaClamp ( float clamp )
      } ;

These calls mostly correspond to similarly named OpenGL functions.

### Enable and Disable calls:

`ssgSimpleState:: disable ( mode )`, `ssgSimpleState:: enable ( mode )` and `ssgSimpleState:: set ( mode, val )` provide the same services as glEnable and glDisable ('set' is a convenience function that is a 'disable' if 'val' is FALSE, 'enable' otherwise). The 'mode' parameter uses tokens that are similarly named to those in OpenGL:

      SSG_GL_TEXTURE_EN
      SSG_GL_CULL_FACE_EN
      SSG_GL_COLOR_MATERIAL_EN
      SSG_GL_BLEND_EN
      SSG_GL_ALPHA_TEST_EN
      SSG_GL_LIGHTING_EN

### Texture states.

There are three ways to attach a texture to an ssgSimpleState: `ssgSimpleState::setTexture ( fname, wrapu, wrapv )`, `ssgSimpleState::setTexture ( ssgtexture )`, and `ssgSimpleState::setTexture ( texture_handle )`. In the form that takes a filename, U-axis wrap and V-axis wrap flags, the texture is loaded from a texture file on disk (see ssgTexture below for details on how this is done). The map will be MIPmapped and set with a texture environment that is GL_LINEAR_MIPMAP_LINEAR and GL_MODULATE.

If you need something fancier, then declare an 'ssgTexture' class and pass that to the setTexture function. You can also load your own texture and pass the OpenGL glBindTexture handle to setTexture.

If you need the texture file name, first check that isEnabled ( GL_TEXTURE_2D ) returns true, then you may call getTextureFilename(). But you should still check the return value for NULL and for "".

### Materials.

These calls are all very similar to OpenGL calls - and take the same parameters: `ssgSimpleState::setColourMaterial(which)` `ssgSimpleState::setMaterial(which,r,g,b,a)` `ssgSimpleState::setMaterial(which,rgba)` `ssgSimpleState::setShininess(sh)` `ssgSimpleState::setShadeModel(model)` `ssgSimpleState::setAlphaClamp(clamp)`

## `class ssgTexture` - Storing texture maps.

An ssgTexture loads a texture map for you with the minimum possible fuss - but offers less flexibility than if you did so yourself.

The ssgTexture constructor function `ssgTexture::ssgTexture( char *fname, int wrapu = TRUE, int wrapv = TRUE )` does all the work, presuming that you require GL_LINEAR_MIPMAP_LINEAR filtering and a GL_MODULATE texture environment.

You can obtain the OpenGL glBindTexture handle for the texture using `ssgTexture::getHandle()`.

When ssgTexture loads a map from disk, it uses the filename extension to determine which image format the file is in.

Currently, only SGI format and uncompressed 8 or 24 bit BMP images are supported - but more formats are planned for the future. Filenames ending with '.rgb', '.rgba', '.int', '.inta', '.bw' are assumed to be SGI formatted files, '.bmp' are in Microsoft's BMP format and '.png' are in Portable Network Graphics format.

If for any reason ssgTexture cannot load the requested file, it creates a 2x2 texel red and white chequerboard map to enable the program to continue running. This is often very useful for debugging and to enable program development to continue when texture maps are not yet painted.

## `class ssgStateSelector` - Switchable State class.

There are cases where you would like to be able to switch between a number of different states for a given leaf node.

      class ssgStateSelector : ssgSimpleState
      {
        ssgStateSelector ( int nstates ) ;

        void            selectStep ( unsigned int s ) ;
        int             getSelectStep  (void) ;
        ssgSimpleState *getCurrentStep (void) ;
        void            setStep ( int i, ssgSimpleState *step ) ;
        ssgSimpleState *getStep ( int i ) ;
      } ;

This class is used to switch between some number of `ssgSimpleStates`. You could (for example) draw the ground for your game as either grass or snow - depending on the season. Construct objects of this class with the number of alternative representations you will require as it's parameter, then create a number of `ssgSimpleState`s - passing them to `ssgStateSelector::setStep()`. You can then select which step you wish to render using `ssgStateSelector::selectStep()`.

`ssgStateSelector::getSelectStep()` returns the number of the currently selected step. `ssgStateSelector::getCurrentStep()` returns a pointer to the currently selected `ssgSimpleState`. `ssgStateSelector::getStep()` returns a pointer to the i'th `ssgSimpleState`.

Since `ssgStateSelector` is derived from `ssgSimpleState`, all the other `ssgSimpleState` calls work - and the effect is to operate on the currently selected `ssgSimpleState`.

Example:

         ssgStateSelector *s = new ssgStateSelector ( 2 ) ;
         ssgSimpleState *grass = new ssgSimpleState () ;
         ssgSimpleState *snow  = new ssgSimpleState () ;

         ...set up grass and snow states appropriately...

         s -> setStep ( 0, grass ) ;
         s -> setStep ( 1, snow  ) ;

         leafnode1 -> setState ( s ) ;
         leafnode2 -> setState ( s ) ;
         leafnode3 -> setState ( s ) ;

         ...choose grass or snow...

         if ( ! winter )
           s -> selectStep ( 0 ) ;
         else
           s -> selectStep ( 1 ) ;

         ...render the scene...

Notice that one selectStep call changes the material on all leaf nodes that use that ssgStateSelector.

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