Creating a Custom VDL


To use a custom VDL, a task must first create a VDL in its own memory. It then submits the VDL to the system, which checks the VDL's integrity and-if it passes-creates a VDL item in system memory. The task can then specify a screen to use that VDL item to control screen display. If the task wants to modify the VDL, it can use a function that changes the VDL item. When the task is finished using the VDL, it can delete the VDL item.

The key to working with custom VDLs is knowing how to write a VDL. To start, you must know how the VDL processor reads a VDL.

VDL Processor Operation

A VDL is divided into discrete parts called VDL entries. The VDL processor can read one VDL entry per display line, which it does during the horizontal blank between lines. When the VDL processor reads a VDL entry, it extracts display information-pointers to bitmap buffers, new colors for CLUT registers, interpolation on or off, and so on. The player also extracts information about where to find the next VDL entry and how many lines will pass before the next VDL entry is read.

When the 3DO hardware is finished reading the VDL entry, the display generator puts up a new frame line using the entry's display parameters. If a VDL entry is specified for the next line, the VDL processor reads that entry during the next horizontal blank, and uses the entry's settings to control the display of the following line. If no VDL entry is specified for a line, the VDL processor keeps the same display settings in effect with one exception: pointers to bitmap buffers.

As you can imagine, if each display line used the same part of the bitmap buffer for its pixels, each line would be identical and you'd end up with a screen full of vertical stripes. To fully display the contents of the bitmap buffer, the pointer to the bitmap buffer must advance through the buffer from line to line. To make this possible, the VDL processor uses two registers: the current bitmap-buffer register and the previous bitmap-buffer register.

As the names imply, one register-the current bitmap-buffer register-stores a pointer to the bitmap buffer used to display the current line. (The current line is the one immediately following a horizontal blank.) The other register-the previous bitmap-buffer register-stores a pointer to the bitmap buffer used to display the previous line. Why does the VDL processor need a pointer to the previous bitmap buffer? Because vertical interpolation between pixels in adjacent lines requires a look at the pixels in the previous line.

As soon as the display generator finishes displaying a line of the frame, the VDL processor automatically increments the contents of the current bitmap-buffer register by a fixed amount (modulo addition). The modulo value, which is typically 320 for a standard 320-by-240 video display, causes the new current bitmap-buffer pointer to skip over 320 pixels-the contents of a single line. When the next line is displayed, it receives a fresh (and consecutive) row of pixels from the bitmap buffer.

Just before the current bitmap-buffer register is incremented, the previous bitmap buffer usually receives the value from the current bitmap-buffer register, which is typically 320 pixels greater than its current value. By rotating the current bitmap-buffer pointer to the previous bitmap-buffer pointer-and then incrementing the current bitmap-buffer pointer-the VDL processor marches its way steadily through a bitmap buffer, displaying its contents line by line, and correctly interpolating between vertically adjacent pixels.

As you'll read in the sections that immediately follow this one, the bitmap-buffer registers' contents and operation can be modified in many ways by a VDL entry. What's important to know about the bitmap-buffer registers is that they're always ticked forward at the end of each line before the VDL processor reads a VDL entry for the next line. The order is

and so on. If a line has no VDL entry, or the entry doesn't change the registers' contents or operation, then the registers' tick forward ensures that the display contains consecutive rows of bitmap-buffer pixels.

VDL Structures

When you create a custom VDL, you must adhere to its structure as well as to the structures of its component parts.

The VDL

A VDL is a collection of VDL entries. Each entry contains commands and information that can be read in the horizontal blank between display lines. A VDL must have at least one VDL entry, but need not have more than one. A simple VDL (used for most standard screens) has just a single VDL entry that sets display parameters for all lines of the screen.

A VDL can have as many VDL entries as there are display lines, but should not have more entries than display lines. If there are fewer VDL entries than there are display lines, some of those entries must persist for more than one display line. The entries themselves can define the length (in lines) of their persistence. If the persistence of the last VDL entry isn't set to last to the end of the display, the VDL processor will increase its persistence to reach to the end of the display.

VDL Entries

A VDL entry is a string of 32-bit words. The string must be no greater than 38 words in length. The string contains

The header words control the VDL processor's operation and DMA access to the bitmap buffer. The following list shows the words in the order in which they must occur:

The length of a VDL entry is limited by the time available to read its words during a horizontal blank. The upper limit of 34 command words allows a VDL entry to change the contents of all 33 CLUT registers, with one command word left over to set other display parameters for the line.

The command words, which are optional for a VDL entry, set CLUT colors and control display generator operation. They need not occur in any particular order, but you should note that if two command words contain contradictory commands (two different colors for the same CLUT register, for example) the later word wins out.

The types of command words are

The CLUT-DMA Control Word

The CLUT DMA control word must be the first word in each VDL entry. It contains the flags shown in Table 1

Table 1:  Bits of the CLUT-DMA.
------------------------------------------------------
Bits    |Operation Controlled                         
------------------------------------------------------
3126    |Not available to a user task. Set to 0.      
------------------------------------------------------
2523    |Sets the modulo value (in words) added to the
        |VDL processor's bitmap-buffer registers.     
        |000=320; 001=384; 010=512; 011=640; 100=1024;
        |101, 110, and 111 are unused.                
------------------------------------------------------
22      |Not available to a user task, set to 0.      
------------------------------------------------------
21      |Enables video DMA.  1=enable, which shows the
        |bitmap-buffer image on the display;          
        |0=disable, which shows only vertical-blank   
        |color on the display.                        
------------------------------------------------------
20      |Not available to a user task. Set to 0.      
------------------------------------------------------
19      |Sets vertical mode. 1=480 lines per frame;   
        |0=240 lines per frame.                       
------------------------------------------------------
18      |Indicates the type of the address stored in  
        |the next VDL-entry-address word. 1=absolute; 
        |0=relative.                                  
------------------------------------------------------
17      |Sets how the previous bitmap-buffer address  
        |register is ticked at line's end. 1=add      
        |modulo amount (set in bits 25-23); 0=accept  
        |current bitmap-buffer address-register value.
------------------------------------------------------
16      |Sets current bitmap-buffer address register  
        |override. 1=load address from current        
        |bitmap-buffer address word; 0=use address    
        |generated by register tick (modulo addition  
        |to last register contents).                  
------------------------------------------------------
15      |Sets previous bitmap-buffer address-register 
        |override. 1=load address from previous       
        |bitmap-buffer address word; 0=use address    
        |generated by register tick (rotated current  
        |bitmap-buffer value or modulo addition to    
        |last register contentsset by bit 17).        
------------------------------------------------------
149     |Gives the number of control words in this VDL
        |entry (total number of VDL entry words minus 
        |the four used for the header). Should be from
        |1 to 34.                                     
------------------------------------------------------
8-0     |Gives the number of display lines this VDL   
        |entry persists. This is the number of lines  
        |the VDL processor waits until reading the    
        |next entry in the VDL. The current line      
        |counts as one. The minimum value is 1 except 
        |for the last VDL entry, which should be 0. (0
        |specifies persistence until the bottom of the
        |screen.)                                     
------------------------------------------------------

Note that any bits listed as "not available" to a user task must be set to 0 or the system will reject the VDL.

What follows is an explanation of the parameters set by the CLUT-DMA control word:

Current Bitmap-Buffer Address Word

This word is a 32-bit value that gives the absolute address of a bitmap buffer to use for this VDL entry's current line. This value is only read if bit 16 of the CLUT DMA control word is set to 1, in which case it overrides the ticked value already written into the register.

Previous Bitmap-Buffer Address Word

This word is a 32-bit value that gives the absolute address of a bitmap buffer to use for the VDL entry's previous. This value is only read if bit 15 of the CLUT DMA control word is set to 1, in which case it overrides the ticked value already written into the register.

Next VDL-Entry-Address Word

This word is a 32-bit value that gives the address of the next VDL entry. Bit 18 of the CLUT-DMA control word determines whether this is a relative or an absolute address. This value is ignored in the last entry of a VDL.

Color-Value Word

A color-value word contains the number of the CLUT register it changes; a flag determining whether it affects the red, green, and blue values together in the register, or any one of those values individually; and 8-bit red, green, and blue values to write into the CLUT register. Table 2 shows how its bits are set up.

Table 2:  Bits of a color-value word.
----------------------------------------------------------
Bits   |Significance                                      
----------------------------------------------------------
31     |Set to 0 to specify that this is a color-value    
       |word.                                             
----------------------------------------------------------
3029   |Determines what parts of a register are written   
       |to. 00=write to all three registers (red, green,  
       |and blue); 01=write to blue only; 10=write to     
       |green only; 11=write to red only.                 
----------------------------------------------------------
2824   |Contains the number (031) of the color register to
       |write to.                                         
----------------------------------------------------------
2316   |Contains 8 bits of red color value with bit 23 as 
       |the most-significant bit.                         
----------------------------------------------------------
158    |Contains 8 bits of green color value with bit 15  
       |as the most-significant bit.                      
----------------------------------------------------------
70     |Contains 8 bits of blue color value with bit 7 as 
       |the most-significant bit.                         
----------------------------------------------------------

If the color-value word is set up to write to only the red, green, or blue part of a register, only the red, green, or blue value contained in the word is used.

Background-Value Word

A VDL entry uses a special command word-the background-value word-to change register 32 (the background register) of the custom CLUT set. The color in this register fills in all pixels detected as background pixels. Table 3 shows how the background-value word's bits are set up.

Table 3:  Bits of a background-value word.
--------------------------------------------------------
Bits   |Significance                                    
--------------------------------------------------------
3124   |Set to 11100000 to specify that this is a       
       |background-value word.                          
--------------------------------------------------------
2316   |Contains eight bits of red color value with bit 
       |23 as the most-significant bit.                 
--------------------------------------------------------
158    |Contains eight bits of green color value with   
       |bit 15 as the most-significant bit.             
--------------------------------------------------------
70     |Contains eight bits of blue color value with bit
       |7 as the most-significant bit.                  
--------------------------------------------------------

The background color register contains a full 24-bit RGB value, so all of bits 23-0 are written to the register when the background-value word is executed by the VDL processor.

Display-Control Word

A display-control word contains flags that set the display generator's operating parameters. Table 4 shows the flags and the operations they control.

Table 4:  Bits of a display-control word.
--------------------------------------------------------
Bits   |Significance                                    
--------------------------------------------------------
3126   |Set to 110000 to specify that this is a         
       |display-control word.                           
--------------------------------------------------------
25     |Makes the fixed CLUT set available.             
       |1=bitmap-buffer pixels with bit 15 set to 1 pass
       |through the fixed CLUT set, those with bit 15   
       |set to 0 pass through the custom CLUT set; 0=all
       |bitmap-buffer pixels pass through the custom    
       |CLUT set (the fixed CLUT set is not available). 
--------------------------------------------------------
24     |Not available to a user task. Set to 0.         
--------------------------------------------------------
23     |Forces pixel transparency. 1=all pixels are     
       |transparent regardless of color value;          
       |0=transparency limited to background pixels (if 
       |enabled by bit 22). This bit is only meaningful 
       |for SlipStream.                                 
--------------------------------------------------------
22     |Sets transparency for background pixels. 1=all  
       |pixels with 000 RGB value (background pixels)   
       |are transparent; 0=all background pixels are not
       |transparent, and are filled with the background 
       |register color. This bit is only meaningful for 
       |SlipStream.                                     
--------------------------------------------------------
21     |For pixels going through the fixed CLUT setswaps
       |the meaning of V and H cornerweight bits. 1=H   
       |value is MSB, V value is LSB; 0=H value is LSB, 
       |V value is MSB.                                 
--------------------------------------------------------
2019   |For pixels going through the fixed CLUT setsets 
       |each pixel's V cornerweight value. 00=set V to  
       |0; 01=set V to 1; 10=use V value stored in      
       |pixel; 11=don't change this setting from the one
       |used by the last VDL entry.                     
--------------------------------------------------------
1817   |For pixels going through the fixed CLUT setsets 
       |each pixel's H cornerweight value. 00=set H to  
       |0; 01=set H to 1; 10=use H value stored in      
       |pixel; 11=don't change this setting from the one
       |used by the last VDL entry.                     
--------------------------------------------------------
1615   |For pixels going through the fixed CLUT setsets 
       |the value of each pixel's least-significant blue
       |bit. 00=set to 1; 01=use bit 5 of the           
       |bitmap-buffer pixel value (the least-significant
       |green bit); 10=use bit 0 of the bitmap-buffer   
       |pixel value; 11=don't change this setting from  
       |the one used by the last VDL entry.             
--------------------------------------------------------
14     |For pixels going through the fixed CLUT         
       |setenables vertical interpolation. 1=vertical   
       |interpolation on; 0=vertical interpolation off. 
--------------------------------------------------------
13     |For pixels going through the fixed CLUT         
       |setenables horizontal interpolation.            
       |1=horizontal interpolation on; 0=horizontal     
       |interpolation off.                              
--------------------------------------------------------
12     |For pixels going through the fixed CLUT         
       |setenables random-number generation to fill in  
       |the three least-significant bits for the 8-bit  
       |red, green, and blue values coming out of the   
       |CLUT set. 1=random number generation on;        
       |0=random number generation off, LSBs filled by  
       |technique determined in bit 11.                 
--------------------------------------------------------
11     |For pixels going through the fixed CLUT         
       |setdetermines how three least-significant bits  
       |for 8-bit red, green, and blue values are filled
       |in. 1=copied from the three most-significant    
       |bits of the color value; 0=set to 000.          
--------------------------------------------------------
10     |For pixels going through the custom CLUT        
       |setswaps the meaning of V and H cornerweight    
       |bits. 1=H value is MSB, V value is LSB; 0=H     
       |value is LSB, V value is MSB.                   
--------------------------------------------------------
98     |For pixels going through the custom CLUT setsets
       |each pixel's V cornerweight value. 00=set V to  
       |0; 01=set V to 1; 10=use V value stored in      
       |pixel; 11=don't change this setting from the one
       |used by the last VDL entry.                     
--------------------------------------------------------
76     |For pixels going through the custom CLUT setsets
       |each pixel's H cornerweight value. 00=set H to  
       |0; 01=set H to 1; 10=use H value stored in      
       |pixel; 11=don't change this setting from the one
       |used by the last VDL entry.                     
--------------------------------------------------------
54     |For pixels going through the custom CLUT setsets
       |the value of each pixel's least-significant blue
       |bit. 00=set to 1; 01=use bit 5 of the           
       |bitmap-buffer pixel value (the least-significant
       |green bit); 10=use bit 0 of the bitmap-buffer   
       |pixel value; 11=don't change this setting from  
       |the one used by the last VDL entry.             
--------------------------------------------------------
3      |For pixels going through the custom CLUT        
       |setenables vertical interpolation. 1=vertical   
       |interpolation on; 0=vertical interpolation off. 
--------------------------------------------------------
2      |For pixels going through the custom CLUT        
       |setenables horizontal interpolation.            
       |1=horizontal interpolation on; 0=horizontal     
       |interpolation off.                              
--------------------------------------------------------
1      |Not available to a user task. Set to zero.      
--------------------------------------------------------

Note that any bits listed as not available to a user task must be set to 0 or the system will reject the VDL.

What follows is an explanation of the display generator parameters set by the display-control word:

NULLOP Word

Occasionally, it may be useful to pad out VDL entries with words that don't cause any VDL processor actions. For example, the SubmitVDL() function described later recommends that VDL entries have a word length that's a multiple of four. The NULLOP word is the perfect way to fill in, it does absolutely nothing. Table 5 shows the bits that don't do the work.

Table 5:  Bits of the NULLOP word.
--------------------------------------------------------
Bits   |Significance                                    
--------------------------------------------------------
3124   |Set to 11100001 to specify that this is a NULLOP
       |word.                                           
--------------------------------------------------------
230    |Have no significance whatsoever. Set to zero.   
--------------------------------------------------------

Writing a VDL

To write a custom VDL, you must think of the screen with which it is associated-does it have uniform properties throughout, or will it be divided into bands of differing properties? You must then decide the properties for each band of the screen, and write a VDL entry to match.

Writing a VDL Entry

One of the most important properties to set in a VDL entry is the relationship of the bitmap buffer to the display. Are there 320, 384, or more pixels per display line? Does the display for this band use 240-line resolution or 480-line resolution, which requires twice as many rows of bitmap-buffer pixels for the same area? Will vertical interpolation occur between subsequent rows of the same bitmap buffer, or is there a separate interpolation buffer to fine-tune the colors of the first bitmap buffer? Does this band get its image from a completely new bitmap buffer, or does it continue displaying pixels from the bitmap buffer used for the previous line? Or does the band not present an image at all and completely ignore the bitmap buffer to put up vertical blank color?

You set all of these bitmap-buffer properties in the CLU- DMA control word, the first word of the VDL entry header. You provide supporting values, if necessary, in the current bitmap-buffer address and previous bitmap-buffer address words.

The combination of properties you set determines how the display generator reads VRAM for an image. You must also set up the data in the specified bitmap buffer (or bitmap buffers) to match the bitmap-buffer properties or you'll get garbage on the screen. For example, if you store an image in VRAM that is 320 pixels wide and then set row width in the CLUT-DMA control word to 384 pixels, you'll see a curiously skewed image on the screen.

Once you've tied the band on the screen to a bitmap buffer in VRAM, you must consider how the display generator handles the pixels in the bitmap buffer. Should it make them all transparent to show underlying images, make just background images transparent, or offer no transparency at all? Should it allow pixels to use the fixed CLUT set so they have a guaranteed color for each pixel, or should it turn the fixed CLUT set off? Should the pixels be interpolated for smooth integration one to the next, or should interpolation be turned off for crispy pixels? Should only the first line escape interpolation to establish a crisp border with the preceding band? How does each pixel determine its cornerweight values? How are missing low-order color bits filled in?

You set these display generator operation properties in a single display-control word. If you use more than one, only the last display-control word in the VDL entry is used for the band. If you don't want to change the display generator operation used in the last band, you can omit a display-control word completely.

You may also want to consider the custom color palette that interprets the bitmap-buffer pixel values. If you want to change the colors in the custom CLUT registers, create an appropriate color-value word for each register change. If you want to change the background color, create an appropriate background-value word. If you create more than one color-value word for a single register, or more than one background-value word, only the last duplicate word in the VDL entry is used-so don't waste command words! You can't have more than 34 command words in a VDL entry. That's just enough to change all 33 CLUT registers and set display generator properties for the band.

Weaving the VDL Entries Into a Complete VDL

When you're finished setting up VDL entries, you must finally set the properties of the VDL entries themselves so they work together as a complete VDL:

These properties are set in the CLUT-DMA control word and the next VDL-entry address word.

Storing VDL Entries

When your task sets up a custom VDL, it stores the VDL words as a one-dimensional array in its own memory. All words within a VDL entry must be in consecutive order. The VDL entries themselves need not be in consecutive order as long as each entry properly points to the next. Note that it doesn't matter where the last entry in the VDL points.

When your task's custom VDL is submitted to the 3DO system, the VDL is checked for integrity and then written to system RAM. Because of alignment constraints in the hardware, VDL entries may not fit correctly in system RAM if their length in words is not a multiple of four.

Your task should pad each VDL entry with NULLOP words at the end of the VDL entry to create a length that's a multiple of four. The CLUT-DMA control-word setting that sets the number of command words in the VDL entry need not include NULLOP pad words. For example, consider a VDL entry with a full complement of 34 command words-it's 38 words long. The task writing it to memory adds two NULLOP words at the end of the entry to bring the entry to 40 words in length. The entry still claims it has 34 command words, so it's a legal entry and not overlong. The NULLOP words are simply not read by the VDL processor when the VDL is used.

Submitting a Screen VDL

Once a task has created a custom VDL, it submits it to the system with this function call:

Item SubmitVDL;( VDLEntry *VDLDataPtr, int32 length, int32 type )
The first argument, VDLDataPtr, is a pointer to a custom VDL data structure. The second argument, length, is the length of the VDL in words. And the third argument, type, gives the type of VDL submitted.

When executed, SubmitVDL() reads the submitted VDL, proofs it for inconsistent or system-crashing settings, and, if it finds none, copies the VDL, into system RAM, as a screen VDL. The call can alter some VDL settings before the VDL becomes an item. For example, if the total persistence for the VDL entries doesn't cover the entire screen, the persistence of the last VDL entry is set to continue to the bottom of the screen. Control-word bits that aren't available to user tasks are also set when the VDL becomes an item.

SubmitVDL() returns an item number for the screen VDL it creates. You can use that item number with a CreateScreenGroup() tag argument to associate the VDL with a newly created screen in a screen group. You can also use the VDL item number to specify the VDL when you modify it or its connections. If unsuccessful, this call returns a negative value (an error code). A task should check for GRAFERR_PROOF_ERR in particular, which indicates that the submitted VDL had illegal control codes or bad data.

Modifying a VDL

To modify the contents of an existing VDL item, use this call:

Err ModifyVDL( Item vdlItem, TagArg* vdlTags )
The first argument, vdlItem, specifies the screen VDL to modify. The second argument, vdlTags, points to a tag argument array that describes the changes to be made to the VDL.

The tag arguments include:

When ModifyVDL() executes, it accepts the tag arguments and writes their arguments to the proper display-control bits of each VDL entry in the VDL. Its effects are VDL-wide; tag argument can't specify a single VDL entry within a VDL (unless, of course, the VDL has only one entry). If successful, the call returns a 0. If unsuccessful, it returns a negative value (an error code).

A task can't modify a screen VDL by modifying the VDL data structure it used to create that VDL. Once created the VDL exists in system RAM and must be modified using ModifyVDL().

Setting a New VDL for an Existing Screen

If you've already created a screen in a screen group and want to assign a different screen VDL to that screen, use this call:

itemSetVDL( Item screenItem, Item vdlItem )
The first argument, screenItem, specifies the item number of the screen to which you want to assign a new screen VDL. The second argument, vdlItem, specifies the screen VDL that you want to assign. When executed, the call assigns the VDL to the screen. When the screen is displayed, its display operation is controlled by its associated VDL. If successful, the call returns a 0. If unsuccessful, it returns the item number of the VDL that was replaced.

Deleting a VDL

To delete a screen VDL and free its resources, use the call DeleteItem() and supply it with the item number of the screen VDL you want to delete. If you delete a VDL that is in use, the screen depending on that VDL goes black.