WELCOME TO S.I.M.O.N

by Steve Baker
SIMON stands for:

     Simple
     Interface for
     Making
     Oliver's programs
     Nice.

This is a simple set of functions that hide much of the nastiness of 3D programming to make it possible for someone with only the very minimum of programming experience to write simple 3D applications.

If you want something more complicated or with better features then don't complain about SIMON - just use raw PLIB (upon which SIMON is based).

HOW TO WRITE YOUR PROGRAM.

You have to write TWO C (or C++) functions:

   int main ()

...and...

   void siUpdate ()

The 'main' function has to load whatever 3D models the program needs and then call a function called 'siRun()'.

siRun does things like opening the 3D window, clearing the screen and drawing all of the models. When it's time to move the models around, it calls your function 'siUpdate'.

All SIMON programs have to start with the line:


   #include <simon.h>

...this brings in all the information the compiler needs in order for you to write a SIMON program. Think of it like '#include <stdio.h>' but for programs that are just doing 3D rendering.

Then, you have to declare an integer variable for everything in the scene that your program needs - which includes at least the scenery and the camera.

For example:


  int camera  ;
  int tux     ;
  int scenery ;
 
Next, you have your 'main' program - which loads up the models and then calls the 'siRun()' function and then exits.

  int main ()
  {
    scenery = siLoad ( "scenery.ac" ) ;
    tux     = siLoad ( "tuxedo.ac"  ) ;

    camera  = 0 ;
 
    siRun () ;
    return 0 ;
  }

The 'siLoad' function loads a 3D model and returns a number for that model that you can save into a variable. That number can be used to move the model around later on. The final part of this 'loading' stage is to set the number for the 'camera'. In SIMON, the camera is always model number zero and you can't 'siLoad' a model for it or it won't work.

Then, you call 'siRun()' - which runs the entire update process. If 'siRun' ever returns, you can just exit the program.

Now we have our scene all set up and ready to go - so the program will call your 'siUpdate' function to move the models (and the camera) around - and then draw the scene.


  int frameno = 0 ;

  void siUpdate ()
  {
    frameno = frameno + 1 ;
 
    siPosition ( tux   , 0,  0, 0, frameno, 0, 0 ) ;
    siPosition ( camera, 0, -5, 1, 0, 0, 0 ) ;
  }
 
Here we defined a simple variable called 'frameno' which is increased by one every time the 'siUpdate' function is called to give the program an idea of how much time has gone by.

Finally, we set the position of the camera and tux by calling 'siPosition' for each of them.

'siPosition' is a function that needs SEVEN things to be passed to it.

  1. The first is the variable that contains the number of the object you want to position.
  2. The second is the X coordinate that you want that object to have (in Meters).
  3. The third is the Y coordinate.
  4. The fourth is the Z coordinate (the height).
  5. The fifth is the 'heading' - which is the direction that the object is pointing. If you model your objects with their noses pointing North in the modeller then this number will be the angle in degrees measured in an anticlockwise direction from due North.
  6. The sixth is the 'pitch' - which is the amount that the object is leaning backwards (in degrees).
  7. The seventh (and last) is the 'roll' - which is the amount that the object is leaning sideways (also in degrees).
That's a lot of information - but it's what you need to tell the object for it to know where to appear in the scene.

In our example program, we first had:


    siPosition ( tux, 0, 0, 0, frameno, 0, 0 ) ;

...which puts Tux at X=0, Y=0, Z=0 (which is at the origin of the scene) and sets his 'heading' equal to this 'frameno' variable. Thus, as time goes on, and we keep adding one to 'frameno', Tux's heading number will gradually increase from zero upwards. This should cause him to rotate in place. Since pitch and roll are both zero, he'll be standing upright.

The slPosition command for the Camera:


    siPosition ( camera, 0, -5, 1, 0, 0, 0 ) ;

...puts the camera at X=0, Y=-5, Z=1 - which is back 5 meters from where Tux is - and one meter up into the air. This should give us a nice view of him as he spins.

READING THE JOYSTICK.

These functions let you read the Left/Right and Up/Down axes of the joystick:

  leftright = siJoystickLR () ;
  updown    = siJoystickUD () ;
 
The numbers that this will put into the variables 'leftright' and 'updown' range from -1.0 to +1.0. Leftwards and Upwards movements generate 1, Rightwards and Downwards movements generate -1, when the stick is in the middle you get zeroes.

To read the buttons, you can use these functions:


  buttonA =  siJoystickA () ;
  buttonB =  siJoystickB () ;
  buttonC =  siJoystickC () ;
  buttonD =  siJoystickD () ;
  buttonL =  siJoystickL () ;
  buttonR =  siJoystickR () ;

...the variables should be 'int' varaibles and will be set to 1 if the button is pressed or 0 if it's not.

OTHER MOVEMENT COMMANDS.

Other commands let you set the Velocity for objects:

    siVelocity ( object, x, y, z, h, p, r ) ;

...and set a speed and a direction:

    siSpeedAndDirection ( object, speed, heading, pitch ) ;

...you can also get the current position for the object:

    x = siGetPositionX ( object ) ;
    y = siGetPositionY ( object ) ;
    z = siGetPositionZ ( object ) ;
    h = siGetPositionH ( object ) ;
    p = siGetPositionP ( object ) ;
    r = siGetPositionR ( object ) ;

THE MAKEFILE.

Once you start to have things like SIMON being used with your program, it can be quite a complicated process to compile your program. It's a lot of typing and you'll make lots of mistakes.

For that reason, Linux uses a command called 'make' to compile complicated programs according to some rules that you tell it in a special file that's called 'Makefile'. Once you have a 'Makefile' set up for your program, you only ever need to type 'make' in order to compile your program - no matter how complicated it gets to be.

A good 'Makefile' for a SIMON program would be:


  #
  # List the names of the programs we want to build here...
  #
  TARGETS = test1
 
  #======================== DON'T CHANGE THIS PART =============================
  #
  SIMONDIR = /usr/local/simon
  SIMON = -I${SIMONDIR} -L${SIMONDIR}
  LIBS  = -lsimon -lplibssg -lplibsg -lplibul -lglut -lGLU -lGL -L/usr/X11/lib -lX11 -lm
 
  all: ${TARGETS}
 
  #=============================================================================
 
  #
  # Copy this for every program you want to write - changing 'test1'
  # to whatever your program is called.
  #
 
  test1 : test1.cxx ; g++ ${SIMON} -o test1 test1.cxx ${LIBS}