Move everything into one directory, update links
This commit is contained in:
parent
b946ff9e70
commit
4eef8b2919
680 changed files with 1638 additions and 1638 deletions
587
46-02.html
Normal file
587
46-02.html
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META name=vsisbn content="1576101746">
|
||||
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
|
||||
<META name=vsauthor content="Michael Abrash">
|
||||
<META name=vspublisher content="The Coriolis Group">
|
||||
<META name=vspubdate content="07/01/97">
|
||||
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: Who Was that Masked Image?</TITLE>
|
||||
|
||||
<!-- HEADER -->
|
||||
<!-- Empty Reference Subhead -->
|
||||
|
||||
<!--ISBN=1576101746//-->
|
||||
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
|
||||
<!--AUTHOR=Michael Abrash//-->
|
||||
<!--PUBLISHER=The Coriolis Group, Inc.//-->
|
||||
<!--CHAPTER=46//-->
|
||||
<!--PAGES=863-871//-->
|
||||
<!--UNASSIGNED1//-->
|
||||
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
||||
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="46-01.html">Previous</A></TD>
|
||||
<TD><A HREF="index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="46-03.html">Next</A></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<P><BR></P>
|
||||
<P><B>LISTING 46.1 L46-1.C</B></P>
|
||||
<!-- CODE //-->
|
||||
<PRE>
|
||||
/* Sample simple dirty-rectangle animation program, partially optimized and
|
||||
featuring internal animation, masked images (sprites), and nonoverlapping dirty
|
||||
rectangle copying. Tested with Borland C++ in the small model. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
#include <alloc.h>
|
||||
#include <memory.h>
|
||||
#include <dos.h>
|
||||
|
||||
/* Comment out to disable overlap elimination in the dirty rectangle list. */
|
||||
#define CHECK-OVERLAP 1
|
||||
#define SCREEN-WIDTH 320
|
||||
#define SCREEN-HEIGHT 200
|
||||
#define SCREEN-SEGMENT 0xA000
|
||||
|
||||
/* Describes a dirty rectangle */
|
||||
typedef struct {
|
||||
void *Next; /* pointer to next node in linked dirty rect list */
|
||||
int Top;
|
||||
int Left;
|
||||
int Right;
|
||||
int Bottom;
|
||||
} DirtyRectangle;
|
||||
/* Describes an animated object */
|
||||
typedef struct {
|
||||
int X; /* upper left corner in virtual bitmap */
|
||||
int Y;
|
||||
int XDirection; /* direction and distance of movement */
|
||||
int YDirection;
|
||||
int InternalAnimateCount; /* tracking internal animation state */
|
||||
int InternalAnimateMax; /* maximum internal animation state */
|
||||
} Entity;
|
||||
/* storage used for dirty rectangles */
|
||||
#define MAX-DIRTY-RECTANGLES 100
|
||||
int NumDirtyRectangles;
|
||||
DirtyRectangle DirtyRectangles[MAX-DIRTY-RECTANGLES];
|
||||
/* head/tail of dirty rectangle list */
|
||||
DirtyRectangle DirtyHead;
|
||||
/* If set to 1, ignore dirty rectangle list and copy the whole screen. */
|
||||
int DrawWholeScreen = 0;
|
||||
/* pixels and masks for the two internally animated versions of the image
|
||||
we’ll animate */
|
||||
#define IMAGE-WIDTH 13
|
||||
#define IMAGE-HEIGHT 11
|
||||
char ImagePixels0[] = {
|
||||
0, 0, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0,
|
||||
0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
|
||||
0, 9, 9, 0, 0,14,14,14, 9, 9, 0, 0, 0,
|
||||
9, 9, 0, 0, 0, 0,14,14,14, 9, 9, 0, 0,
|
||||
9, 9, 0, 0, 0, 0,14,14,14, 9, 9, 0, 0,
|
||||
9, 9,14, 0, 0,14,14,14,14, 9, 9, 0, 0,
|
||||
9, 9,14,14,14,14,14,14,14, 9, 9, 0, 0,
|
||||
9, 9,14,14,14,14,14,14,14, 9, 9, 0, 0,
|
||||
0, 9, 9,14,14,14,14,14, 9, 9, 0, 0, 0,
|
||||
0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
|
||||
0, 0, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0,
|
||||
};
|
||||
char ImageMask0[] = {
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
};
|
||||
char ImagePixels1[] = {
|
||||
0, 0, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9,
|
||||
0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9,
|
||||
0, 9, 9, 0, 0,14,14,14, 9, 9, 9, 9, 0,
|
||||
9, 9, 0, 0, 0, 0,14,14,14, 0, 0, 0, 0,
|
||||
9, 9, 0, 0, 0, 0,14,14, 0, 0, 0, 0, 0,
|
||||
9, 9,14, 0, 0,14,14,14, 0, 0, 0, 0, 0,
|
||||
9, 9,14,14,14,14,14,14, 0, 0, 0, 0, 0,
|
||||
9, 9,14,14,14,14,14,14,14, 0, 0, 0, 0,
|
||||
0, 9, 9,14,14,14,14,14, 9, 9, 9, 9, 0,
|
||||
0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9,
|
||||
0, 0, 0, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9,
|
||||
};
|
||||
char ImageMask1[] = {
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
};
|
||||
/* Pointers to pixel and mask data for various internally animated
|
||||
versions of our animated image. */
|
||||
char * ImagePixelArray[] = {ImagePixels0, ImagePixels1};
|
||||
char * ImageMaskArray[] = {ImageMask0, ImageMask1};
|
||||
/* Animated entities */
|
||||
#define NUM-ENTITIES 15
|
||||
Entity Entities[NUM-ENTITIES];
|
||||
/* pointer to system buffer into which we’ll draw */
|
||||
char far *SystemBufferPtr;
|
||||
/* pointer to screen */
|
||||
char far *ScreenPtr;
|
||||
void EraseEntities(void);
|
||||
void CopyDirtyRectanglesToScreen(void);
|
||||
void DrawEntities(void);
|
||||
void AddDirtyRect(Entity *, int, int);
|
||||
void DrawMasked(char far *, char *, char *, int, int, int);
|
||||
void FillRect(char far *, int, int, int, int);
|
||||
void CopyRect(char far *, char far *, int, int, int, int);
|
||||
|
||||
void main()
|
||||
{
|
||||
int i, XTemp, YTemp;
|
||||
unsigned int TempCount;
|
||||
char far *TempPtr;
|
||||
union REGS regs;
|
||||
/* Allocate memory for the system buffer into which we’ll draw */
|
||||
if (!(SystemBufferPtr = farmalloc((unsigned int)SCREEN-WIDTH*
|
||||
SCREEN-HEIGHT))) {
|
||||
printf(”Couldn’t get memory\n”);
|
||||
exit(1);
|
||||
}
|
||||
/* Clear the system buffer */
|
||||
TempPtr = SystemBufferPtr;
|
||||
for (TempCount = ((unsigned)SCREEN-WIDTH*SCREEN-HEIGHT); TempCount--; ) {
|
||||
*TempPtr++ = 0;
|
||||
}
|
||||
/* Point to the screen */
|
||||
ScreenPtr = MK-FP(SCREEN-SEGMENT, 0);
|
||||
/* Set up the entities we’ll animate, at random locations */
|
||||
randomize();
|
||||
for (= 0; < NUM-ENTITIES; i++) {
|
||||
Entities[i].X = random(SCREEN-WIDTH - IMAGE-WIDTH);
|
||||
Entities[i].Y = random(SCREEN-HEIGHT - IMAGE-HEIGHT);
|
||||
Entities[i].XDirection = 1;
|
||||
Entities[i].YDirection = -1;
|
||||
Entities[i].InternalAnimateCount = & 1;
|
||||
Entities[i].InternalAnimateMax = 2;
|
||||
}
|
||||
/* Set the dirty rectangle list to empty, and set up the head/tail node
|
||||
as a sentinel */
|
||||
NumDirtyRectangles = 0;
|
||||
DirtyHead.Next = &DirtyHead;
|
||||
DirtyHead.Top = 0x7FFF;
|
||||
DirtyHead.Left= 0x7FFF;
|
||||
DirtyHead.Bottom = 0x7FFF;
|
||||
DirtyHead.Right = 0x7FFF;
|
||||
/* Set 320x200 256-color graphics mode */
|
||||
regs.x.ax = 0x0013;
|
||||
int86(0x10, &regs, &regs);
|
||||
/* Loop and draw until a key is pressed */
|
||||
do {
|
||||
/* Draw the entities to the system buffer at their current locations,
|
||||
updating the dirty rectangle list */
|
||||
DrawEntities();
|
||||
/* Draw the dirty rectangles, or the whole system buffer if
|
||||
appropriate */
|
||||
CopyDirtyRectanglesToScreen();
|
||||
/* Reset the dirty rectangle list to empty */
|
||||
NumDirtyRectangles = 0;
|
||||
DirtyHead.Next = &DirtyHead;
|
||||
/* Erase the entities in the system buffer at their old locations,
|
||||
updating the dirty rectangle list */
|
||||
EraseEntities();
|
||||
/* Move the entities, bouncing off the edges of the screen */
|
||||
for (= 0; < NUM-ENTITIES; i++) {
|
||||
XTemp = Entities[i].X + Entities[i].XDirection;
|
||||
YTemp = Entities[i].Y + Entities[i].YDirection;
|
||||
if ((XTemp < 0) || ((XTemp + IMAGE-WIDTH) > SCREEN-WIDTH)) {
|
||||
Entities[i].XDirection = -Entities[i].XDirection;
|
||||
XTemp = Entities[i].X + Entities[i].XDirection;
|
||||
}
|
||||
if ((YTemp < 0) || ((YTemp + IMAGE-HEIGHT) > SCREEN-HEIGHT)) {
|
||||
Entities[i].YDirection = -Entities[i].YDirection;
|
||||
YTemp = Entities[i].Y + Entities[i].YDirection;
|
||||
}
|
||||
Entities[i].X = XTemp;
|
||||
Entities[i].Y = YTemp;
|
||||
}
|
||||
} while (!kbhit());
|
||||
getch(); /* clear the keypress */
|
||||
|
||||
/* Return back to text mode */
|
||||
regs.x.ax = 0x0003;
|
||||
int86(0x10, &regs, &regs);
|
||||
}
|
||||
/* Draw entities at their current locations, updating dirty rectangle list. */
|
||||
void DrawEntities()
|
||||
{
|
||||
int i;
|
||||
char far *RowPtrBuffer;
|
||||
char *TempPtrImage;
|
||||
char *TempPtrMask;
|
||||
Entity *EntityPtr;
|
||||
|
||||
for (= 0, EntityPtr = Entities; < NUM-ENTITIES; i++, EntityPtr++) {
|
||||
/* Remember the dirty rectangle info for this entity */
|
||||
AddDirtyRect(EntityPtr, IMAGE-HEIGHT, IMAGE-WIDTH);
|
||||
/* Point to the destination in the system buffer */
|
||||
RowPtrBuffer = SystemBufferPtr + (EntityPtr->Y * SCREEN-WIDTH) +
|
||||
EntityPtr->X;
|
||||
/* Advance the image animation pointer */
|
||||
if (++EntityPtr->InternalAnimateCount >=
|
||||
EntityPtr->InternalAnimateMax) {
|
||||
EntityPtr->InternalAnimateCount = 0;
|
||||
}
|
||||
/* Point to the image and mask to draw */
|
||||
TempPtrImage = ImagePixelArray[EntityPtr->InternalAnimateCount];
|
||||
TempPtrMask = ImageMaskArray[EntityPtr->InternalAnimateCount];
|
||||
DrawMasked(RowPtrBuffer, TempPtrImage, TempPtrMask, IMAGE-HEIGHT,
|
||||
IMAGE-WIDTH, SCREEN-WIDTH);
|
||||
}
|
||||
}
|
||||
/* Copy the dirty rectangles, or the whole system buffer if appropriate,
|
||||
to the screen. */
|
||||
void CopyDirtyRectanglesToScreen()
|
||||
{
|
||||
int i, RectWidth, RectHeight;
|
||||
unsigned int Offset;
|
||||
DirtyRectangle * DirtyPtr;
|
||||
if (DrawWholeScreen) {
|
||||
/* Just copy the whole buffer to the screen */
|
||||
DrawWholeScreen = 0;
|
||||
CopyRect(ScreenPtr, SystemBufferPtr, SCREEN-HEIGHT, SCREEN-WIDTH,
|
||||
SCREEN-WIDTH, SCREEN-WIDTH);
|
||||
} else {
|
||||
/* Copy only the dirty rectangles, in the YX-sorted order in which
|
||||
they’re linked */
|
||||
DirtyPtr = DirtyHead.Next;
|
||||
for (= 0; < NumDirtyRectangles; i++) {
|
||||
/* Offset in both system buffer and screen of image */
|
||||
Offset = (unsigned int) (DirtyPtr->Top * SCREEN-WIDTH) +
|
||||
DirtyPtr->Left;
|
||||
/* Dimensions of dirty rectangle */
|
||||
RectWidth = DirtyPtr->Right - DirtyPtr->Left;
|
||||
RectHeight = DirtyPtr->Bottom - DirtyPtr->Top;
|
||||
/* Copy a dirty rectangle */
|
||||
CopyRect(ScreenPtr + Offset, SystemBufferPtr + Offset,
|
||||
RectHeight, RectWidth, SCREEN-WIDTH, SCREEN-WIDTH);
|
||||
/* Point to the next dirty rectangle */
|
||||
DirtyPtr = DirtyPtr->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Erase the entities in the system buffer at their current locations,
|
||||
updating the dirty rectangle list. */
|
||||
void EraseEntities()
|
||||
{
|
||||
int i;
|
||||
char far *RowPtr;
|
||||
|
||||
for (= 0; < NUM-ENTITIES; i++) {
|
||||
/* Remember the dirty rectangle info for this entity */
|
||||
AddDirtyRect(&Entities[i], IMAGE-HEIGHT, IMAGE-WIDTH);
|
||||
/* Point to the destination in the system buffer */
|
||||
RowPtr = SystemBufferPtr + (Entities[i].Y * SCREEN-WIDTH) +
|
||||
Entities[i].X;
|
||||
/* Clear the rectangle */
|
||||
FillRect(RowPtr, IMAGE-HEIGHT, IMAGE-WIDTH, SCREEN-WIDTH, 0);
|
||||
}
|
||||
}
|
||||
/* Add a dirty rectangle to the list. The list is maintained in top-to-bottom,
|
||||
left-to-right (YX sorted) order, with no pixel ever included twice, to minimize
|
||||
the number of display memory accesses and to avoid screen artifacts resulting
|
||||
from a large time interval between erasure and redraw for a given object or for
|
||||
adjacent objects. The technique used is to check for overlap between the
|
||||
rectangle and all rectangles already in the list. If no overlap is found, the
|
||||
rectangle is added to the list. If overlap is found, the rectangle is broken
|
||||
into nonoverlapping pieces, and the pieces are added to the list by recursive
|
||||
calls to this function. */
|
||||
void AddDirtyRect(Entity * pEntity, int ImageHeight, int ImageWidth)
|
||||
{
|
||||
DirtyRectangle * DirtyPtr;
|
||||
DirtyRectangle * TempPtr;
|
||||
Entity TempEntity;
|
||||
int i;
|
||||
if (NumDirtyRectangles >= MAX-DIRTY-RECTANGLES) {
|
||||
/* Too many dirty rectangles; just redraw the whole screen */
|
||||
DrawWholeScreen = 1;
|
||||
return;
|
||||
}
|
||||
/* Remember this dirty rectangle. Break up if necessary to avoid
|
||||
overlap with rectangles already in the list, then add whatever
|
||||
rectangles are left, in YX sorted order */
|
||||
#ifdef CHECK-OVERLAP
|
||||
/* Check for overlap with existing rectangles */
|
||||
TempPtr = DirtyHead.Next;
|
||||
for (= 0; < NumDirtyRectangles; i++, TempPtr = TempPtr->Next) {
|
||||
if ((TempPtr->Left < (pEntity->X + ImageWidth)) &&
|
||||
(TempPtr->Right > pEntity->X) &&
|
||||
(TempPtr->Top < (pEntity->Y + ImageHeight)) &&
|
||||
(TempPtr->Bottom > pEntity->Y)) {
|
||||
|
||||
/* We’ve found an overlapping rectangle. Calculate the
|
||||
rectangles, if any, remaining after subtracting out the
|
||||
overlapped areas, and add them to the dirty list */
|
||||
/* Check for a nonoverlapped left portion */
|
||||
if (TempPtr->Left > pEntity->X) {
|
||||
/* There’s definitely a nonoverlapped portion at the left; add
|
||||
it, but only to at most the top and bottom of the overlapping
|
||||
rect; top and bottom strips are taken care of below */
|
||||
TempEntity.X = pEntity->X;
|
||||
TempEntity.Y = max(pEntity->Y, TempPtr->Top);
|
||||
AddDirtyRect(&TempEntity,
|
||||
min(pEntity->Y + ImageHeight, TempPtr->Bottom) -
|
||||
TempEntity.Y,
|
||||
TempPtr->Left - pEntity->X);
|
||||
}
|
||||
/* Check for a nonoverlapped right portion */
|
||||
if (TempPtr->Right < (pEntity->X + ImageWidth)) {
|
||||
/* There’s definitely a nonoverlapped portion at the right; add
|
||||
it, but only to at most the top and bottom of the overlapping
|
||||
rect; top and bottom strips are taken care of below */
|
||||
TempEntity.X = TempPtr->Right;
|
||||
TempEntity.Y = max(pEntity->Y, TempPtr->Top);
|
||||
AddDirtyRect(&TempEntity,
|
||||
min(pEntity->Y + ImageHeight, TempPtr->Bottom) -
|
||||
TempEntity.Y,
|
||||
(pEntity->X + ImageWidth) - TempPtr->Right);
|
||||
}
|
||||
/* Check for a nonoverlapped top portion */
|
||||
if (TempPtr->Top > pEntity->Y) {
|
||||
/* There’s a top portion that’s not overlapped */
|
||||
TempEntity.X = pEntity->X;
|
||||
TempEntity.Y = pEntity->Y;
|
||||
AddDirtyRect(&TempEntity, TempPtr->Top - pEntity->Y, ImageWidth);
|
||||
}
|
||||
/* Check for a nonoverlapped bottom portion */
|
||||
if (TempPtr->Bottom < (pEntity->Y + ImageHeight)) {
|
||||
/* There’s a bottom portion that’s not overlapped */
|
||||
TempEntity.X = pEntity->X;
|
||||
TempEntity.Y = TempPtr->Bottom;
|
||||
AddDirtyRect(&TempEntity,
|
||||
(pEntity->Y + ImageHeight) - TempPtr->Bottom, ImageWidth);
|
||||
}
|
||||
/* We’ve added all non-overlapped portions to the dirty list */
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CHECK-OVERLAP */
|
||||
/* There’s no overlap with any existing rectangle, so we can just
|
||||
add this rectangle as-is */
|
||||
/* Find the YX-sorted insertion point. Searches will always terminate,
|
||||
because the head/tail rectangle is set to the maximum values */
|
||||
TempPtr = &DirtyHead;
|
||||
while (((DirtyRectangle *)TempPtr->Next)->Top < pEntity->Y) {
|
||||
TempPtr = TempPtr->Next;
|
||||
}
|
||||
while ((((DirtyRectangle *)TempPtr->Next)->Top == pEntity->Y) &&
|
||||
(((DirtyRectangle *)TempPtr->Next)->Left < pEntity->X)) {
|
||||
TempPtr = TempPtr->Next;
|
||||
}
|
||||
/* Set the rectangle and actually add it to the dirty list */
|
||||
DirtyPtr = &DirtyRectangles[NumDirtyRectangles++];
|
||||
DirtyPtr->Left = pEntity->X;
|
||||
DirtyPtr->Top = pEntity->Y;
|
||||
DirtyPtr->Right = pEntity->X + ImageWidth;
|
||||
DirtyPtr->Bottom = pEntity->Y + ImageHeight;
|
||||
DirtyPtr->Next = TempPtr->Next;
|
||||
TempPtr->Next = DirtyPtr;
|
||||
}
|
||||
</PRE>
|
||||
<!-- END CODE //-->
|
||||
<P><B>LISTING 46.2 L46-2.ASM</B></P>
|
||||
<!-- CODE //-->
|
||||
<PRE>
|
||||
; Assembly language helper routines for dirty rectangle animation. Tested with
|
||||
; TASM.
|
||||
; Fills a rectangle in the specified buffer.
|
||||
; C-callable as:
|
||||
; void FillRect(char far * BufferPtr, int RectHeight, int RectWidth,
|
||||
; int BufferWidth, int Color);
|
||||
;
|
||||
.model small
|
||||
.code
|
||||
parms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;pushed return address
|
||||
BufferPtr dd ? ;far pointer to buffer in which to fill
|
||||
RectHeight dw ? ;height of rectangle to fill
|
||||
RectWidth dw ? ;width of rectangle to fill
|
||||
BufferWidth dw ? ;width of buffer in which to fill
|
||||
Color dw ? ;color with which to fill
|
||||
parms ends
|
||||
public -FillRect
|
||||
-FillRectproc near
|
||||
cld
|
||||
push bp
|
||||
mov bp,sp
|
||||
push di
|
||||
|
||||
les di,[bp+BufferPtr]
|
||||
mov dx,[bp+RectHeight]
|
||||
mov bx,[bp+BufferWidth]
|
||||
su bx,[bp+RectWidth] ;distance from end of one dest scan
|
||||
; to start of next
|
||||
mov al,byte ptr [bp+Color]
|
||||
mov ah,al ;double the color for REP STOSW
|
||||
RowLoop:
|
||||
mov cx,[bp+RectWidth]
|
||||
shr cx,1
|
||||
rep stosw
|
||||
adc cx,cx
|
||||
rep stosb
|
||||
add di,bx ;point to next scan to fill
|
||||
dec dx ;count down rows to fill
|
||||
jnz RowLoop
|
||||
|
||||
pop di
|
||||
pop bp
|
||||
ret
|
||||
-FillRect endp
|
||||
|
||||
; Draws a masked image (a sprite) to the specified buffer. C-callable as:
|
||||
; void DrawMasked(char far * BufferPtr, char * Pixels, char * Mask,
|
||||
; int ImageHeight, int ImageWidth, int BufferWidth);
|
||||
parms2 struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;pushed return address
|
||||
BufferPtr2 dd ? ;far pointer to buffer in which to draw
|
||||
Pixels dw ? ;pointer to image pixels
|
||||
Mask dw ? ;pointer to image mask
|
||||
ImageHeight dw ? ;height of image to draw
|
||||
ImageWidth dw ? ;width of image to draw
|
||||
BufferWidth2 dw ? ;width of buffer in which to draw
|
||||
parms2 ends
|
||||
public -DrawMasked
|
||||
-DrawMasked proc near
|
||||
cld
|
||||
push bp
|
||||
mov bp,sp
|
||||
push si
|
||||
push di
|
||||
|
||||
les di,[bp+BufferPtr2]
|
||||
mov si,[bp+Mask]
|
||||
mov bx,[bp+Pixels]
|
||||
mov dx,[bp+ImageHeight]
|
||||
mov ax,[bp+BufferWidth2]
|
||||
su ax,[bp+ImageWidth] ;distance from end of one dest scan
|
||||
mov [bp+BufferWidth2],ax ; to start of next
|
||||
RowLoop2:
|
||||
mov cx,[bp+ImageWidth]
|
||||
ColumnLoop:
|
||||
lods ;get the next mask byte
|
||||
and al,al ;draw this pixel?
|
||||
jz SkipPixel ;no
|
||||
mov al,[bx] ;yes, draw the pixel
|
||||
mov es:[di],al
|
||||
SkipPixel:
|
||||
inc bx ;point to next source pixel
|
||||
inc d ;point to next dest pixel
|
||||
dec cx
|
||||
jnz ColumnLoop
|
||||
add di,[bp+BufferWidth2] ;point to next scan to fill
|
||||
dec dx ;count down rows to fill
|
||||
jnz RowLoop2
|
||||
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
ret
|
||||
-DrawMasked endp
|
||||
|
||||
; Copies a rectangle from one buffer to another. C-callable as:
|
||||
; void CopyRect(DestBufferPtr, SrcBufferPtr, CopyHeight, CopyWidth,
|
||||
; DestBufferWidth, SrcBufferWidth);
|
||||
|
||||
parms3 struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;pushed return address
|
||||
DestBufferPtr dd ? ;far pointer to buffer to which to copy
|
||||
SrcBufferPtr dd ? ;far pointer to buffer from which to copy
|
||||
CopyHeight dw ? ;height of rect to copy
|
||||
CopyWidth dw ? ;width of rect to copy
|
||||
DestBufferWidth dw ? ;width of buffer to which to copy
|
||||
SrcBufferWidth dw ? ;width of buffer from which to copy
|
||||
parms3 ends
|
||||
public -CopyRect
|
||||
-CopyRect proc near
|
||||
cld
|
||||
push bp
|
||||
mov bp,sp
|
||||
push si
|
||||
push di
|
||||
push ds
|
||||
|
||||
les di,[bp+DestBufferPtr]
|
||||
lds si,[bp+SrcBufferPtr]
|
||||
mov dx,[bp+CopyHeight]
|
||||
mov bx,[bp+DestBufferWidth] ;distance from end of one dest scan
|
||||
su bx,[bp+CopyWidth] ; of copy to the next
|
||||
mov ax,[bp+SrcBufferWidth] ;distance from end of one source scan
|
||||
su ax,[bp+CopyWidth] ; of copy to the next
|
||||
RowLoop3:
|
||||
mov cx,[bp+CopyWidth] ;# of bytes to copy
|
||||
shr cx,1
|
||||
rep movsw ;copy as many words as possible
|
||||
adc cx,cx
|
||||
rep movs ;copy odd byte, if any
|
||||
add si,ax ;point to next source scan line
|
||||
add di,bx ;point to next dest scan line
|
||||
dec dx ;count down rows to fill
|
||||
jnz RowLoop3
|
||||
|
||||
pop ds
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
ret
|
||||
-CopyRect endp
|
||||
end
|
||||
</PRE>
|
||||
<!-- END CODE //-->
|
||||
<P><BR></P>
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="46-01.html">Previous</A></TD>
|
||||
<TD><A HREF="index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="46-03.html">Next</A></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
|
||||
<hr width="90%" size="1" noshade>
|
||||
<div align="center">
|
||||
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book © 2001 Michael Abrash</font>
|
||||
</div>
|
||||
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
|
||||
<!-- reference_subfoot = footer -->
|
||||
<!-- reference_footer = subfoot -->
|
||||
|
||||
<!-- BEGIN SUB FOOTER -->
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
<!-- END FOOTER -->
|
||||
|
||||
|
||||
Loading…
Reference in a new issue