Warning: Using -g disables the optimizer.
3DO Data Types
As you start writing your first programs, you'll find it helpful to have information about available 3DO datatypes. Here's a table of commonly used datatypes:
Table 1: 3DO data types and what they mean --------------------------------------------- 3DO type |Meaning --------------------------------------------- char |unsigned 8-bit --------------------------------------------- uchar, ubyte, uint8 |char --------------------------------------------- bool, Boolean |char --------------------------------------------- int8 |signed char --------------------------------------------- int32 |32-bit integer --------------------------------------------- uint32 |unsigned int32 --------------------------------------------- int64 |struct {uint32 hi; |uint32 lo} --------------------------------------------- Coord |int32 --------------------------------------------- Item |int32 --------------------------------------------- Err |int32 --------------------------------------------- frac16, frac30, |int32 frac14 | --------------------------------------------- ufrac16, ufrac30, |unit32 ufrac14 | --------------------------------------------- int64, uint64, | frac32, ufrac32 | --------------------------------------------- frac60, ufrac60 | ---------------------------------------------
Note that working with 3DO types requires some care. For example, many of the fields of the CCB structure have int32 arguments. Upon closer examination you will find, however, that some of them (for example the ccb_HDX and ccb_HDY field), are 12.20 numbers. Others (for example the ccb_VDX and ccb_VDY field) are 16.16 numbers.
In general, it is best to use the type int32 and int16, and convert all references to int, long, or short values into precisely sized type definitions. The sample code currently included on the CD-ROM uses this technique sporadically.
Note: All 16-bit datatypes are very inefficient on the ARM processor. It is much faster to use 32-bit datatypes instead.
Efficient Display Using Cel Lists
The jsshowcel example program displays only one image and one cel. This is a very unusual situation. Usually, an application shows many cels on the screen, displaying quite a few at start-up and adding and removing them as needed. A solution to speeding up cel display is working with cel lists.
Once triggered by a DrawCels()
call, the cel engine renders every cel in a list until it encounters the final cel, which has the CCB_LAST flag in ccb_Flags field turned on. You can establish a cel list by setting the ccb_NextPtr field in the CCB of a cel, to point to the CCB of the next cel to render and clearing the CCB_LAST flag of each cel except the last one.
Be sure to set the CCB_LAST flag in the ccb_Flags field of the last CCB in the list; if you don't, the cel engine never stops. (The code fragment below sets the ccb_NextPtr field of the last cel to NULL, in addition to setting CCB_LAST. Just setting ccb_NextPtr to NULL is insufficient; the code fragment does it because it's convenient for traversing the cel list in software.)
When the program starts up and displays the UFO, it effectively displays the other cels as well. Since there is a good deal of overhead involved in starting and stopping the cel engine, you should call DrawCels()
only once per frame for maximum speed (30 frames per second). Take full advantage of the cel list. Set up the complete list, then make a single call to DrawCels()
to process the list.
The code fragment below, which comes from InitGame()
in jsinteractivesound.c, sets up a cel list. It sets the ccb_NextPtr
field of each CCB to a pointer to the CCB of the next cel. Once a cel is drawn, it's part of the background, so the last cel in the list appears in front of all the other cels in the list.
Example 1: Setting up a cel list
/* Link the UFO, laser, crosshairs, and cockpit cels: */
LinkCel(gUFOCel, gLaserCel);
LinkCel(gLaserCel, gCrosshairsCel);
LinkCel(gCrosshairsCel, gCockpitCel);
LAST_CEL(gCockpitCel);