An Overview of Frame Programming


Recall from the overview chapters that 3DO's display generator is controlled by the VDL (video display list) processor, a component of the Portfolio Graphics folio. The VDL processor reads a VDL containing display commands that can affect each line of the frame. Each display command is tied to a specific line, and is executed during the horizontal blanking before that line. The commands can change many different frame display parameters: they point to a beginning frame buffer address or the line, choose a CLUT set, change a color palette, and more. When a display command changes a display parameter, the change applies to all following screen lines until another display command at another line changes the parameter again.

Setting up a frame on a 3DO system is primarily a matter of creating a VDL that sets the proper graphics context for the frame contents. That's why many of the graphics function calls create and modify the VDL either directly or indirectly. Because the VDL can-if set up incorrectly-crash the system, Portfolio takes over all responsibility for the master VDL. A user task can create its own VDL with a graphics function call; the VDL is submitted to Portfolio, which reads it, analyzes its information and commands, and then either accepts the VDL or rejects it for errors. Once accepted, the VDL is copied into system RAM, where it is assigned an item number. This VDL is called a screen VDL (the name is explained later in this chapter).

A task can create more than one screen VDL, and multiple tasks can each create their own screen VDLs, so the system can contain many screen VDLs. Portfolio uses these screen VDLs to create the master VDL. It can use one screen VDL at a time, switching from one to the other to display different frame contents, or it can combine screen VDLs in the master VDL to display parts of multiple images in a single frame.

Screens

The heart of frame programming involves creating a screen, a structure that is-simply put-a single VDL with an accompanying bitmap (or bitmaps) to store image pixels. A screen fills the width of the display, typically 320 pixels across in a video display, and can be from 1 to more than 240 lines high. A screen less than 240 lines high leaves a blank area on the bottom of the display; a screen more than 240 lines high is clipped past line 240. (Future Portfolio releases may allow the screens to start below the top of the display.)

When a task requires a screen, it uses a single graphics call (CreateScreenGroup()) to create the screen. The call specifies a standard screen; Portfolio creates the appropriate VDL and bitmap for the screen, and the task then proceeds to write into the screen. If the task requires a special screen, it can use the same call to specify a custom VDL, to set a screen size less than 240 lines high, and to create one or more custom bitmaps to place in the screen. You'll find details later in this chapter.

Bitmaps

A bitmap within a screen has two parts: a bitmap buffer in VRAM that holds pixel contents; and the bitmap definition that specifies the height, width, and other characteristics of the bitmap. When the cel engine projects a cel or when a drawing function creates a geometric shape, they write pixels into the bitmap buffer of the screen's bitmap.

Although a screen typically uses only a single bitmap, it can use two or more bitmaps if it wishes to divide itself into discrete horizontal bands as shown in Figure 1. The screen specifies where each bitmap is positioned.

Graphic cannot be displayed

Figure 1: Positioning of bitmaps.

A screen has a single VDL and one or more bitmaps. Screen 1 on the left is a typical screen with a single bitmap. Screen 2 on the right is an exotic version with three bitmaps.

A bitmap can stretch 320 pixels across, exactly filling the screen width, or it can be more narrow or wider than the screen. A bitmap wider than 320 pixels will have its right most columns truncated; a bitmap narrower than 320 pixels will be set flush against the left edge of the screen, leaving columns of 000 pixels in the right side of the screen.

A screen divided into two or more bitmaps can restrict cel projections to specific bitmaps, and can also restrict double-buffering (as explained later) to specific bitmaps to reduce processing time.

Screen Groups

Because many tasks need to swap between two screens for double-buffered animation or need to switch among even more screens for effects such as stereoscopic 3-D, a screen is always created as part of a screen group, a group of screens through which the task can switch to display any screen. A screen group can have just a single screen within it, or two, three, four, or even more screens. Each of the screens in the group has the same configuration of bitmaps, dimensions, and display characteristics. The screen group is presented to the frame as a single unit with one of its screens selected as the display screen.

A screen group provides a screen VDL for each of its screens. When a task switches display from one screen in the group to another screen, Portfolio takes the new display screen VDL and incorporates it into the master VDL in place of the previous display screen VDL.

Double-Buffering

Double-buffered animation-the most common type of 3DO animation-traditionally uses two screens; it's best achieved using a two-screen group. Drawing and cel projection calls render into the bitmap of one screen while the second screen is displayed in the frame. The screens are then swapped so the newly rendered screen is on display while the old screen is rendered with the next image. By constantly drawing into the undisplayed screen and then swapping, no drawing occurs directly in a displayed screen, which might show some unsightly artifacts as pixel rendering coincides with pixel reading.

To present a stereoscopic 3-D image, Portfolio swaps between two images (one for the left eye and one for the right eye) 60 times a second. An interlaced video signal doesn't present more than 30 frames per second, so 3DO divides each frame into its two component fields and presents one stereoscopic image in the odd field and the other stereoscopic image in the even field.

Portfolio doesn't require a special screen group for stereoscopic 3-D; a task can put its left and right images in a standard screen group. The function call that displays the screen group determines whether the group is displayed by field (60 times a second for stereophonic 3-D) or by frame (30 times a second). If the group is displayed by field, two screens effectively appear on the display simultaneously.

To create double-buffered stereoscopic animation, a screen group needs at least three but usually four screens so that the task can render into an undisplayed screen while two other screens are displayed.

Multiple Screen Groups in a Frame

The 3DO system can present more than one screen group within a single frame. Several tasks running simultaneously can each put a screen group into the frame; or a single task can put two or more screen groups in the frame at once. When two or more screen groups appear in the same frame, they are layered, one on top of the other. Each screen group has a vertical offset from the top of the frame:

If an overlaying screen group's size or offset reveals an underlying screen group, the underlying screen group shows through. Portfolio currently only allows an offset of 0 for a screen.

When Portfolio prepares the master VDL for a frame containing multiple screen groups, it works one line at a time. It looks to see which part of which screen group shows at each line, and uses the appropriate information from the visible screen's VDL to create a line entry (if necessary) for the master VDL. The master VDL can then switch palettes, color sets, and VRAM pointers from line to line to display the visible sections of the multiple screen groups.

The screen group and its independent positioning is a very useful tool in the frame environment. A task doesn't need to concern itself with the screen group's position in the frame when the task draws to a screen-it simply sees the screen as an independent canvas for drawing, and isn't concerned if the screen group is moved so that part of it is hidden above or below the frame boundaries, or is covered by another screen group.

The screen group offers another advantage when it comes to changing its position in the frame: all the screens within the screen group (if there are more than one) move with the group. The task doesn't have to set individual screen positions for all the screens in a group.

Examples

Almost all graphics tasks use a standard screen group configuration: a screen group containing two 320-by-240 screens for double-buffered animation as shown in Figure 2. Each of those screens contains a single VDL and an accompanying bitmap. The task doesn't use 3-D display, and swaps the two screens every 1/30 of a second (during the vertical interrupt). This configuration is simple and easy to implement.

Graphic cannot be displayed

Figure 2: The standard double-buffered screen group configuration.

A few graphics tasks opt for complexity to suit their specific needs. For example, a flight simulator may need to split its screens into three bitmaps as shown in Figure 3: a middle band for the constantly changing view from the cockpit, and the top and bottom bands for slowly changing cockpit controls. It uses a screen group with two screens. Screen 1 and screen 2 both specify the same top bitmap and the same bottom bitmap (their VDLs both point to the same buffer). They specify separate bitmaps as the middle bitmap. When the task swaps between the screens, the top and bottom bitmaps don't change because both screens point to the same bitmaps. The middle bitmap does change, though, because the VDL of each screen points to a different bitmap. This kind of screen segmentation reduces the VRAM required for double-buffering.

Graphic cannot be displayed

Figure 3: Screen group.

A complex screen group configuration provides three bitmaps per screen with double-buffering set only for the middle bitmap (bitmaps 3 and 4 alternate in Figure 3). Cel projection can be limited to the middle bitmap or can extend to the entire screen.

Multiple bitmaps on a screen also help confine cel projection to certain parts of the screen. One cel projection call (DrawCels()) specifies to which bitmap within a screen you'd like to project. In a flight simulator, you can project outside object cels (such as other flying planes) only on the middle bitmap. If the cels move beyond the bitmap's boundaries, they're clipped. Another call (DrawScreenCels()) projects a all of a screen's bitmaps to hit the entire screen. For example, you may want to project a cel of smoke filling the cockpit onto the entire screen.