134 lines
7.9 KiB
Markdown
134 lines
7.9 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](49-02.html) [Table of Contents](index.html) [Next](49-04.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
It would be handy to have a function that, given a base image and mask,
|
||
generates the four image and mask alignments and fills in the
|
||
**MaskedImage** structure. Listing 49.3, together with the include file
|
||
in Listing 49.4 and the system memory-to-display memory block-copy
|
||
routine in Listing 48.4 (in the previous chapter) does just that. It
|
||
would be faster if Listing 49.3 were in assembly language, but there’s
|
||
no reason to think that generating aligned images needs to be
|
||
particularly fast; in such cases, I prefer to use C, for reasons of
|
||
coding speed, fewer bugs, and maintainability.
|
||
|
||
**LISTING 49.3 L49-3.C**
|
||
|
||
/* Generates all four possible mode X image/mask alignments, stores image
|
||
alignments in display memory, allocates memory for and generates mask
|
||
alignments, and fills out an AlignedMaskedImage structure. Image and mask must
|
||
both be in byte-per-pixel form, and must both be of width ImageWidth. Mask
|
||
maps isomorphically (one to one) onto image, with each 0-byte in mask masking
|
||
off corresponding image pixel (causing it not to be drawn), and each non-0-byte
|
||
allowing corresponding image pixel to be drawn. Returns 0 if failure, or # of
|
||
display memory addresses (4-pixel sets) used if success. For simplicity,
|
||
allocated memory is not deallocated in case of failure. Compiled with
|
||
Borland C++ in C compilation mode. */
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include “maskim.h”
|
||
|
||
extern void CopySystemToScreenX(int, int, int, int, int, int, char *,
|
||
unsigned int, int, int);
|
||
unsigned int CreateAlignedMaskedImage(MaskedImage * ImageToSet,
|
||
unsigned int DispMemStart, char * Image, int ImageWidth,
|
||
int ImageHeight, char * Mask)
|
||
{
|
||
int Align, ScanLine, BitNum, Size, TempImageWidth;
|
||
unsigned char MaskTemp;
|
||
unsigned int DispMemOffset = DispMemStart;
|
||
AlignedMaskedImage *WorkingAMImage;
|
||
char *NewMaskPtr, *OldMaskPtr;
|
||
/* Generate each of the four alignments in turn. */
|
||
for (Align = 0; Align < 4; Align++) {
|
||
/* Allocate space for the AlignedMaskedImage struct for this alignment. */
|
||
if ((WorkingAMImage = ImageToSet->Alignments[Align] =
|
||
malloc(sizeof(AlignedMaskedImage))) == NULL)
|
||
return 0;
|
||
WorkingAMImage->ImageWidth =
|
||
(ImageWidth + Align + 3) / 4; /* width in 4-pixel sets */
|
||
WorkingAMImage->ImagePtr = DispMemOffset; /* image dest */
|
||
/* Download this alignment of the image. */
|
||
CopySystemToScreenX(0, 0, ImageWidth, ImageHeight, Align, 0,
|
||
Image, DispMemOffset, ImageWidth, WorkingAMImage->ImageWidth * 4);
|
||
/* Calculate the number of bytes needed to store the mask in
|
||
nibble (Map Mask-ready) form, then allocate that space. */
|
||
Size = WorkingAMImage->ImageWidth * ImageHeight;
|
||
if ((WorkingAMImage->MaskPtr = malloc(Size)) == NULL)
|
||
return 0;
|
||
/* Generate this nibble oriented (Map Mask-ready) alignment of
|
||
the mask, one scan line at a time. */
|
||
OldMaskPtr = Mask;
|
||
NewMaskPtr = WorkingAMImage->MaskPtr;
|
||
for (ScanLine = 0; ScanLine < ImageHeight; ScanLine++) {
|
||
BitNum = Align;
|
||
MaskTemp = 0;
|
||
TempImageWidth = ImageWidth;
|
||
do {
|
||
/* Set the mask bit for next pixel according to its alignment. */
|
||
MaskTemp |= (*OldMaskPtr++ != 0) << BitNum;
|
||
if (++BitNum > 3) {
|
||
*NewMaskPtr++ = MaskTemp;
|
||
MaskTemp = BitNum = 0;
|
||
}
|
||
} while (--TempImageWidth);
|
||
/* Set any partial final mask on this scan line. */
|
||
if (BitNum != 0) *NewMaskPtr++ = MaskTemp;
|
||
}
|
||
DispMemOffset += Size; /* mark off the space we just used */
|
||
}
|
||
return DispMemOffset - DispMemStart;
|
||
}
|
||
|
||
**LISTING 49.4 MASKIM.H**
|
||
|
||
/* MASKIM.H: structures used for storing and manipulating masked
|
||
images */
|
||
|
||
/* Describes one alignment of a mask-image pair. */
|
||
typedef struct {
|
||
int ImageWidth; /* image width in addresses in display memory (also
|
||
mask width in bytes) */
|
||
unsigned int ImagePtr; /* offset of image bitmap in display mem */
|
||
char *MaskPtr; /* pointer to mask bitmap */
|
||
} AlignedMaskedImage;
|
||
|
||
/* Describes all four alignments of a mask-image pair. */
|
||
typedef struct {
|
||
AlignedMaskedImage *Alignments[4]; /* ptrs to AlignedMaskedImage
|
||
structs for four possible destination
|
||
image alignments */
|
||
} MaskedImage;
|
||
|
||
#### Notes on Masked Copying {#Heading5}
|
||
|
||
Listings 49.1 and 49.2, like all Mode X code I’ve presented, perform no
|
||
clipping, because clipping code would complicate the listings too much.
|
||
While clipping can be implemented directly in the low-level Mode X
|
||
routines (at the beginning of Listing 49.1, for instance), another,
|
||
potentially simpler approach would be to perform clipping at a higher
|
||
level, modifying the coordinates and dimensions passed to low-level
|
||
routines such as Listings 49.1 and 49.2 as necessary to accomplish the
|
||
desired clipping. It is for precisely this reason that the low-level
|
||
Mode X routines support programmable start coordinates in the source
|
||
images, rather than assuming (0,0); likewise for the distinction between
|
||
the width of the image and the width of the area of the image to draw.
|
||
|
||
Also, it would be more efficient to make up structures that describe the
|
||
source and destination bitmaps, with dimensions and coordinates built
|
||
in, and simply pass pointers to these structures to the low level,
|
||
rather than passing many separate parameters, as is now the case. I’ve
|
||
used separate parameters for simplicity and flexibility.
|
||
|
||
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
 *Be aware that as nifty as Mode X hardware-assisted masked copying is, whether or not it’s actually faster than software-only masked or transparent copying depends upon the processor and the video adapter. The advantage of Mode X masked copying is the 32-bit parallelism; the disadvantages are the need to read display memory and the need to perform an **OUT** for every four pixels. (**OUT** is a slow 486/Pentium instruction, and most VGAs respond to **OUT**s much more slowly than to display memory writes.)*
|
||
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](49-02.html) [Table of Contents](index.html) [Next](49-04.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|