Extracting Cel Source Data from an Existing Image


One of a cel's most powerful features is the ability to use existing source data as its own source data. The most common instance of this is for a set of cels to use a single-source data file. For example, a driving game may allow the player to see other cars driving ahead. Each of those cars can be projected as a separate cel, each with its own CCB. Each CCB, however, points to the same source data file, which contains the single image of a car. Each car on the screen has the same appearance, but because each cel's CCB can specify a different location and projection quadrilateral, they appear in different sizes and spots on the screen. To help further differentiate the cars, each CCB can use a different PLUT, or it may tint the source data differently in the pixel processor so that each car cel appears with a different color as well.

Not all source data sharing is as simple as the previous example, which assumes that each cel uses the same source data dimensions, that is, each cel uses the full car as its source data image. A cel can use just part of an existing source data file, such as the wheel of a car cel. Or a cel might use a section of a bitmap to copy part of existing images on a screen. For example, a program could select a subrectangle of a photographic image on the screen and then magnify the subrectangle by projecting it as an enlarged cel. To extract a subrectangle of cel source data from an existing image, you must set the proper source data pointer in the CCB and set appropriate cel dimensions and offsets in the preamble.

Setting a CCB for Data Extraction

When you extract cel source data from an existing image, you probably cannot use an existing preamble. If the image is in a bitmap, the preamble does not exist; and if the image is a subrectangle of another cel's source data, the preamble will not correctly define the subrectangle. Therefore, you must specify that this cel's preamble will appear at the end of the CCB. To do so, set the CCBPRE flag of the CCB's FLAGS word to 1. You must also specify that this cel is unpacked (you cannot extract a subrectangle from packed data) by setting the PACKED flag of FLAGS to 0.

The CCB must point to the address of the word where the first subrectangle pixel appears. To find that address within a bitmap, you can use the GetPixelAddress() call, which accepts bitmap coordinates of a pixel and returns the absolute address of the word where the pixel is stored. You then set the SPABS flag of FLAGS to 1, which specifies an absolute cel source data pointer, and add the address to the CCB in the SOURCEPTR word.

Your next task is to create the appropriate two-word preamble for the source data and store them as the PRE0 and PRE1 words of the CCB.

Creating a Preamble for Extracted Data

The preamble contains the dimensions used to define the subrectangle and the offsets that skip over words and pixels between the end of one row and the beginning of the next row.

To define the width of the subrectangle, figure the number of pixels in a row do the following:

  1. Subtract 1.
  2. Add the number of pixels that must be skipped for alignment reasons
  3. Put the result in HPCNT of the second preamble word.
To define the height, figure the number of rows in the subrectangle, do the following:

  1. Subtract one
  2. Put the result in VCNT of the first preamble word.
Figure 1 shows how to extract a subrectangle example. The width is 6 pixels, but one pixel is skipped for a total of 7, so HPCNT = 6; the height is 3 pixels, so VCNT = 2.

Graphic cannot be displayed

Figure 1: Extracting a subrectangle.

In Figure 1, the source data pointer in the CCB determines the starting word of the source data. You must set the SKIPX value in the first preamble word the number of pixels necessary to get to the first pixel of the subrectangle. If the first subrectangle pixel falls on the word boundary, you do not need to skip any pixels, and SKIPX = 0. If the first pixel falls after the word boundary, you need to skip one or more pixels by setting SKIPX appropriately. In the example in Figure 2, which uses 16-bit pixels that are stored two to a word, the subrectangle starts in the second half of a word. Setting SKIPX to 1 tells the cel engine to skip the first pixel within the starting word of each row so the subrectangle starts on the second pixel of the word.

Note: Pixels skipped by SKIPX are part of the HPCNT value.

The cel engine uses the dimension set with HPCNT to count pixels as it projects a row of pixels; when it is finished counting the row, it uses the WOFFSET value (in the second preamble word) to calculate the address of the beginning word of the next row, and then moves there. The cel engine uses SKIPX again to skip any pixels necessary within the row's first word to get to the beginning pixel.

To determine WOFFSET, count full words only from the beginning of one row to the beginning of the next, subtract 2, and then enter the value as WOFFSET. In the example in Figure 2, the word offset is 7, which is the word count from the beginning of one subrectangle row to the beginning of the next subrectangle row. (It is also the full width in words of the original source data.) After subtracting 2, WOFFSET = 5. For cels of 1-, 2-, 4-, and 6-bpp, use WOFFSET(8) to store the word offset value; for cels of 8- or 16-bpp, use WOFFSET(10). If you're extracting a subrectangle from a 16-bpp uncoded bitmap such as the frame buffer, you need to set LRFORM to 1 in the second preamble word so the cel engine can handle the left/right format of the pixels stored there.

Once you've defined a subrectangle with the source data pointer, vertical and horizontal dimensions, and the word and pixel offsets, you must make sure that the rest of the preamble data matches the format of the pixels you're using in the subrectangle. Set UNCODED, REP8, BPP, and other preamble values appropriately.

Note: When extracting a subrectangle from 6-bit source data, do not set WOFFSET to point to a word boundary that falls in the middle of a 6-bit pixel. Because the 32 bits of a word are not divided evenly by 6, some 6-bit pixels are split across word boundaries. Word beginnings and 6-bit pixel beginnings coincide every third word (word 0, word 3, word 6, word 9, and so on), so you should safely point to the beginning of a pixel as long as the CCB's pointer to the source data correctly points to a word beginning that does not divide a 6-bit pixel.