Graphics Programming Black Book-Gpbb49
Graphics Programming Black Book-Gpbb49
chapter 49
Masked Copying
Over the past two chapters, we’ve put together most of the tools needed to imple-
ment animation in the VGA’s undocumented 320x240 256-color Mode X. We now
have mode set code, solid and 4x4 pattern fills, system memory-to-display memory
block copies, and display memory-to-display memory block copies. The final piece
915
of the puzzle is the ability to copy a nonrectangular image to display memory.I call
this masked copying.
Masked copying is sort of like drawing through a stencil, in that only certain pixels
within the destination rectangle are drawn. The objective isto fit the image seamlessly
into thebackground, without the rectangular fringe that results when nonrectangular
images are drawn by block copying their bounding rectangle. This is accomplished
by using a second rectangular bitmap, separate fromthe image but corresponding
to it on a pixel-by-pixel basis, to control which destination pixels are set from the
source and which are left unchanged. With a masked copy, only those pixels prop-
erly belonging to an image are drawn, and the image fits perfectly into the
background, with no rectangular border. In fact, masked copying even makesit pos-
sible to havetransparent areaswithin images.
Note that anotherway to achieve this effect is to implement copying code that sup-
ports a transparent color; that is, a color that doesn’t get copiedbut ratherleaves the
destination unchanged. Transparent copying makes for more compactimages, be-
cause no separate mask is needed, and is generally faster in a software-only
implementation. However, Mode X supports masked copying but not transparent
copying in hardware, so we’ll use masked copying in this chapter.
The system memory to display memory masked copy routine in Listing 49.1 imple-
ments masked copying in a straightforward fashion. In the main drawing loop, the
corresponding mask byte is consulted as each image pixel is encountered, and the
image pixel is copied only if the mask byteis nonzero. As with most of the system-to-
display code I’ve presented, Listing 49.1 is not heavily optimized, because it’s
inherently slow; there’s a better way to go when performance matters, and that’s to
use the VGA’s hardware.
v o i d CopySystemToScreenMaskedX(int S o u r c e S t a r t X .
i n tS o u r c e S t a r t Y .i n tS o u r c e E n d X .i n tS o u r c e E n d Y .
i n tD e s t S t a r t X .i n tD e s t S t a r t Y .c h a r * SourcePtr.
u n s i g n e di n tD e s t P a g e B a s e .i n tS o u r c e B i t m a p W i d t h .
i n t D e s t B i t m a p W i d t h .c h a r * MaskPtr):
SC-INDEX 03c4h equ : S e q u e n c eC o n t r o l l e rI n d e xr e g i s t e rp o r t
MAP-MASK :index
02h
equ i n SC o f Map Mask r e g i s t e r
SCREEN-SEG equ OaOOOh :segmentd i sopf l a y memory i n mode X
parms struc
dw 2 dup ( ? ) :pushed BP and r e t ua rdnd r e s s
SourceStartX dw ? :X c osocouroulpdoerpifonfcntefearrt e
: ( s o u r c ei si ns y s t e m memory)
916 Chapter 49
SourceStartY dw ? ;Y c o o r d i n a t eo fu p p e rl e f tc o r n e ro fs o u r c e
SourceEndX dw ? ;X c o o r d i n a t e o f l o w e r r i g h t c o r n e r o f s o u r c e
; ( t h ec o l u m na t EndX i s n o t c o p i e d )
SourceEndY dw ? ; Y c o o r d i n a t eo fl o w e rr i g h tc o r n e ro fs o u r c e
: ( t h er o wa t EndY i s n o t c o p i e d )
DestStartX dw ? ;X c o o r d i n a t eo fu p p e rl e f tc o r n e ro fd e s t
; ( d e s t i n a t i o ni si nd i s p l a y memory)
DestStartY dw ? ;Y c o o r d i n a t eo fu p p e rl e f tc o r n e ro fd e s t
SourcePtr dw ? ; p o i n t e r i n DS t o s t a r t o f b i t m a p w h i c h s o u r c e r e s i d e s
DestPageBase dw ? :base o f f s e t i n d i s p l a y memory o f page i n
; w h i c hd e s tr e s i d e s
SourceBitmapWidth dw ? ;# o fp i x e l sa c r o s ss o u r c eb i t m a p( a l s om u s t
: b ew i d t ha c r o s st h em a s k )
DestBi
tmapWidth dw ? ; # o fp i x e l sa c r o s sd e s tb i t m a p( m u s tb em u l t i p l eo f4 )
MaskPtr dw ? ; p o i n t e r i n DS t o s t a r t o f b i t m a p i n w h i c h mask
: r e s i d e s( b y t e - p e r - p i x e lf o r m a t ,j u s tl i k et h es o u r c e
i m a g e ;0 - b y t e s mean d o n ' tc o p yc o r r e s p o n d i n gs o u r c e
p i x e l , 1 - b y t e s mean docopy)
parms
ends
-2 equ
RectWidth :1 o c a ls t o r a g ef o rw i d t ho fr e c t a n g l e
- 4 R eecqtuH e i g h t ;1 o c a ls t o r a g ef o rh e i g h to fr e c t a n g l e
LeftMask equ -6 :1 o c a ls t o r a g ef o rl e f tr e c te d g ep l a n e mask
STACK-FRAME-SIZE equ 6
.model smal 1
.code
p u b l i c -CopySystemToScreenMaskedX
-CopySystemToScreenMaskedX pnr eo ac r
f r a m e s t a c kc a l;lppush erre' ss e r v e b p
f r a smt ea cl okmov c a l t o ; p ob iPn*ts P
sub [Link]-FRAME-SIZE ; a l l o c a st ep a cf loeor c vaal r s
v a r ri ae bg licesa:st pelpush
l reer s' se r v es i
push di
mov ax.[bp+DestBitmapWidthl
shr ax, 1 a d d r ei nswsied:stchtoon v e r t
shr ax.1
mov [bp+DestBitmapWidth].ax;rememberaddresswidth
mu1 [bp+DestStartYl : t o pd e s tr e c ts c a nl i n e
mov di.[bp+DestStartX]
mov
shr
shr
[Link]
d i .1
d i .1
;X/4 -
offsetoffirstdestrectpixelin
; s c a nl i n e
add d i ,ax ; o f f s e to ff i r s td e s tr e c tp i x e li n page
add [Link]+OestPageBasel :offsetoffirstdestrectpixel
and
mo v
cl .Ollb
a1 . l l h
: i n d i s p l a y memory
;CL
: u p p e rn i b b l e
-
firstdestpixel'splane
comes i n t o p l a y when p l a n ew r a p s
; f r o m 3 b a c kt o 0
sh l a1 . c l :setthebitforthefirstdestpixel'splane
mov [bp+[Link] : i n e a c hn i b b l et o 1
918 Chapter 49
There’s a slight hitch, though. The latches can only be used when the source and
destination left edge coordinates, modulo four, are the same, as explained in the
previous chapter. The solution is to copy allfour possible alignments of each image
to display memory, each properly positioned for one of the four possible destina-
tion-left-edge-modulo-four [Link] aligned images must be accompaniedby the
four possible alignments of the image mask,stored in system memory. Given all four
image and mask alignments, masked copying is a simple matter of selecting the align-
ment that’s appropriate for the destination’s left edge, then setting the Map Mask
with the 4bit mask corresponding to each four-pixel set as we copy four pixels at a
time via the latches.
Listing 49.2 performs fast masked [Link] code expects to receivea pointer to
a MaskedImage structure, which in turn points to fourAlignedMaskedImage struc-
tures that describe the fourpossible imageand mask alignments. The aligned images
are already stored in display memory, and the aligned masks are already stored in
system memory; further, the masks are predigested into Map Mask register-compat-
ible form. Given all that ready-to-use data, Listing 49.2 selects and works with the
appropriate image-mask pair for thedestination’s left edge alignment.
LISTING [Link]
: Mode X ( 3 2 0 x 2 4 0 .2 5 6c o l o r s )d i s p l a y memory t o d i s p l a y memorymaskedcopy
: r o u t i n e . Workson a l l VGAs. Uses approach o fr e a d i n g 4 p i x e l s a t a t i m ef r o m
: s o u r c ei n t ol a t c h e s ,t h e nw r i t i n gl a t c h e st od e s t i n a t i o n ,u s i n g Map Mask
: r e g i s t e rt op e r f o r mm a s k i n g .C o p i e su pt ob u tn o ti n c l u d i n gc o l u m na t
: SourceEndXandrow a t SourceEndY. No c l i p p i n gi sp e r f o r m e d .R e s u l t sa r en o t
: g u a r a n t e e d i f s o u r c ea n dd e s t i n a t i o no v e r l a p . C n e a r - c a l l a b l ea s :
: v o i d CopyScreenToScreenMaskedX(int S o u r c e S t a r t X .
i n tS o u r c e S t a r t Y .i n t SourceEndX. i n t SourceEndY.
i n tD e s t S t a r t X ,i n tO e s t S t a r t Y .M a s k e d I m a g e * Source,
u n s i g n e di n tD e s t P a g e B a s e .i n tD e s t B i t m a p W i d t h ) :
SC-INDEX 03c4h : S e q u e n c eC o n t r o l l e rI n d e xr e g i s t e rp o r t
MAP-MASK 02h : i n d e x i n SC o f Map Mask r e g i s t e r
GC-INDEX 03ceh ; G r a p h i c sC o n t r o l l e rI n d e xr e g i s t e rp o r t
BIT-MASK 08h ; i n d e x i n GC o f Bit Mask r e g i s t e r
SCREENKSEG OaOODh :segment o f d i s p l a y memory i n mode X
parms struc
2 dup ( ? ) ;pushed B P and r e t u r na d d r e s s
SourceStartX ? : X c o o r d i n a t eo fu p p e rl e f tc o r n e ro fs o u r c e
SourceStartY ? :Y c o o r d i n a t e o f u p p e r l e f t c o r n e r o f s o u r c e
SourceEndX ? :X c o o r d i n a t e o f l o w e r r i g h t c o r n e r o f s o u r c e
: ( t h ec o l u m na tS o u r c e E n d X i sn o tc o p i e d )
SourceEndY ? ; Y c o o r d i n a t eo fl o w e rr i g h tc o r n e ro fs o u r c e
: ( t h e rowatSourceEndY i sn o tc o p i e d )
DestStartX ? ; X c o o r d i n a t eo fu p p e rl e f tc o r n e ro fd e s t
DestStartY ? :Y c o o r d i n a t eo fu p p e rl e f tc o r n e r o f dest
Source ? : p o i n t e r t o MaskedImage s t r u c t f o r s o u r c e
: w h i c hs o u r c er e s i d e s
DestPageBase 1 : b a s eo f f s e ti nd i s p l a y memory o f page i n
: w h i c hd e s tr e s i d e s
DestBitmapWidth ? ;#o f p i x e l s a c r o s s d e s t b i t m a p ( m u s t b e m u l t i p l e o f 4)
parms
ends
cld
mov [Link]-INDEX ; stbhei et mask s teol eba cil tlts
mov [Link]+BIT-MASK ; f r otm
hl ae t c h easnndo nf reo m
out [Link] : t h e CPU. so t h a t we wtchraietne
; l a t c hc o n t e n t sd i r e c t l yt o memory
mov [Link]-SEG : p o i n t ES d i st op l a y memory
mov [Link]
mov ax.[bp+DestBitmapWidthl
a d d r e s isne sw i dshr
t h t:oc o n av ex .r 1t
shr ax.1
mu1 [ b p + D e s t S t a ;drrstteolY
ciscpnal ten
mov di.[bp+DestStartXl
mov
shr
shr
si ,di
d i .1
d i .1
;X/4
; scan l i n e
- o ff idforrsepsefesitictxtnte l
920 Chapter 49
mov [Link]
add si.[bx+MaskPtrl : p o i n t t o mask o f f s e t o f f i r s t mask p i x e l i n OS
mov bx.[bx+ImagePtrl ; o f f s e to ff i r s ts o u r c er e c tp i x e l
add [Link] : i n d i s p l a y memory
mov ax,[bp+SourceStartXl : c a l c u l a t e # o f a d d r e s s e sa c r o s s
add ax,cx ; r e c t .s h i f t i n g i f n e c e s s a r yt o
add cx,[bp+SourceEndX] ; a c c o u n tf o ra l i g n m e n t
CmP [Link]
jle CopyDone ; s k i p i f 0 o rn e g a t i v ew i d t h
add cx.3
and a x . n o tO l l b
sub [Link]
shr cx. 1
shr cx.1 ;# o f a d d r e s s e sa c r o s sr e c t a n g l et oc o p y
mov
-
ax.[bp+SourceEndYl
sub [Link]+SourceStartYl :AX h e i g h to fr e c t a n g l e
jle CopyDone ; s k i p i f 0 o rn e g a t i v eh e i g h t
mov [bp+[Link]
mov ax.[bp+DestBitmapWidthl
a d d r e sisne sw i sd ht hr t; oc o nav xe.r1t
shr ax.1
sub a x . :cdxi s t a n fcreoem ononddf essct al isnt toenaoerftx t
mov Cbp+[Link]
mov ax.[bp+SourceBitmapWidthl ; wai di ntdhr e s s e s
sub a x .: cd xi s t a nf cr eoenmd o f s o u r sc ce al isnnt toeanoreftx t
mov [bp+[Link]
mov Cbp+[Link] ;remember width i n addresses
mov [Link]-INDEX
mov a1 ,MAP"MASK
out ; [Link] SC Ir ne dgteiosx t e r Map Mask
t oinc
;point dx r eSC
g i sDt ea rt a
CopyRowsLoop:
mov cx.[bp+RectAddrWidthl ; w i d t ha c r o s s
CopyScanLineLoop:
lodsb : g e tt h e mask f o r t h i s f o u r - D i x e l s e t
: - a n da d v a n c et h e mask p o i n t e r
the o: suett [Link] mask
mov a1 . e s : [;bl olxtahal tedc hwfeoi tsuh r - p fisxrseoeotm lu r c e
mov e s : [ d ;fi c][Link]-eyttposi ex te l
p o i n t esro u r c e t h e : aidncv a n c e b x
inc di pdoeisnttienra t itohne; a d v a n c e
s ef ot su r - p i x eol f f ; cdec ount cx
jnz CopyScanLineLoop
mov ax,[bp+SourceNextScanOffset]
o f s t a r t t h eadd t o ; p osi in,ta x
add [Link] s o u r c e n, e x t : t h e mask,
add di.[bp+DestNextScanOffsetl : a nddelsi nt e s
dec word p[ tbrp + R e c t H e i g h: ct lo u n t down s c al inn e s
j nz CopyRowsLoop
CopyDone:
mov [Link]-INDEX+l ; r e s t otbhr ieet mask idt eos f a u l t ,
mov a1 . O f f h ; w hsi ec lhbfera ti cohtl stlm
es CPU
out [Link] l a (ttcthfh:hnreeoeoam
snned GC
; I n d e xs t i l lp o i n t st oB i t Mask)
v a r ri ae bg licesatsle:l rePOPer 'sst o r e d i
POP si
v a r imovl ao bc lael sf s;odtroi sr [Link]
It would be handy to have a function that, given a base image and mask, generates
the fourimage and mask alignments and fills in the MaskedImage structure. Listing
49.3,together with the includefile in Listing 49.4and thesystem memory-to-display
memory block-copy routine in Listing 48.4 (in theprevious chapter) does just that.
It would be faster if Listing 49.3were 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.
# i n c l u d e< s t d i o . h >
#i n c l ude < s t d l ib. h>
#include"maskim.h"
e x t e r nv o i d CopySystemToScreenX(int, i n t . i n t . i n t . i n t . i n t . c h a r *,
u n s i g n e di n t ,i n t .i n t ) ;
u n s i g n e d i n t CreateAlignedMaskedImage(Masked1mage * ImageToSet.
u n s i g n e di n tD i s p M e m S t a r t .c h a r * Image, i n t Imagewidth.
i n t I m a g e H e i g h t .c h a r * Mask)
(
i n tA l i g n ,S c a n L i n e .B i t N u m .S i z e ,T e m p I m a g e W i d t h ;
-
u n s i g n e dc h a r MaskTemp;
u n s i g n e di n tD i s p M e m O f f s e t DispMemStart;
A1 ignedMaskedImage *WorkingAMImage;
char*NewMaskPtr.*OldMaskPtr:
f o r( A l i g n -
I* G e n e r a t ee a c ho ft h ef o u ra l i g n m e n t si nt u r n .
0: A l i g n < 4;Align++) I
*I
i f ((WorkingAMImage -
/ * A l l o c a t es p a c ef o rt h eA l i g n e d M a s k e d I m a g es t r u c tf o rt h i sa l i g n m e n t .
ImageToSet->AlignmentsCAlignl
malloc(sizeof(AlignedMasked1mage))) -- NULL)
-
*/
r e t u r n 0;
WorkingAMImage->Imagewidth -
-
( I m a g e w i d t h + A l i g n + 3 ) / 4; / * w i d t h i n 4 - p i x e l s e t s
W o r k i n g A M I m a g e - > I m a g e P t r DispMemOffset: I* i m a g ed e s t */
/ * Download t h i sa l i g n m e n to ft h ei m a g e . */
*/
CopySystemToScreenX(0, 0. I m a g e w i d t h I. m a g e H e i g h t A , lign, 0.
Image,[Link]. WorkingAMImage->Imagewidth * 4);
/ * C a l c u l a t e t h e number o f b y t e s n e e d e d t o s t o r e t h e mask i n
n i b b l e (Map M a s k - r e a d y )f o r m ,t h e na l l o c a t et h a ts p a c e . */
-
Size WorkingAMImage->Imagewidth * ImageHeight:
i f ((WorkingAMImage->MaskPtr
r e t u r n 0;
-
malloc(Size)) - NULL)
922 Chapter 49
/* G e n e r a t et h i sn i b b l eo r i e n t e d (Map M a s k - r e a d y )a l i g n m e n to f
--
t h e mask,onescan
OldMaskPtr Mask:
l i n e a t a t i m e . */
---
NewMaskPtr WorkingAMImage->MaskPtr:
f o r( S c a n L i n e 0: ScanLine < ImageHeight:ScanLine++) {
BitNum Align:
MaskTemp 0:
TempImageWidth - Imagewidth:
do {
/ * S e tt h e mask b i t f o r n e x t p i x e l a c c o r d i n g t o i t s a l i g n m e n t . */
MaskTemp I- (*OldMaskPtr++ !- 0 ) << BitNum:
i f (++BitNum > 3 ) {
1
*NewMaskPtr++
MaskTemp - - -
BitNum
MaskTemp:
0:
1 w h i l e( - - T e m p I m a g e W i d t h ) :
1
/* S e ta n yp a r t i a lf i n a l maskon
i f ( B i t N u m !- 0 ) *NewMaskPtr++ - t h i ss c a nl i n e .
MaskTemp:
*/
/* D e s c r i b e so n ea l i g n m e n to f a m a s k - i m a g ep a i r . */
t y p e d e fs t r u c t {
i n tI m a g e w i d t h : / * i m a g ew i d t hi na d d r e s s e si nd i s p l a y memory ( a l s o
mask w i d t h i n b y t e s ) */
u n s i g n e di n tI m a g e P t r : / * o f f s e t o f imagebitmap i n d i s p l a y mem */
char*MaskPtr; / * p o i n t e rt o maskbitmap */
1 AlignedMaskedImage;
/ * D e s c r i b e sa l lf o u ra l i g n m e n t so f a m a s k - i m a g ep a i r . */
t y p e d e fs t r u c t {
AlignedMaskedImage*Alignments[41: /* p t r st oA l i g n e d M a s k e d I m a g e
s t r u c t sf o rf o u rp o s s i b l ed e s t i n a t i o n
i m a g ea l i g n m e n t s */
1 MaskedImage:
Animation
Gosh. There’s just no way I can discuss high-level animation fundamentals in any
detail here; I could spend an entire (andentirely separate) bookon animation tech-
niques alone. You might want to have a look at Chapters 43 through 46 before
attacking the code inthis chapter; thatwill have to do us for the presentvolume. (I
will return to 3-Danimation in the next chapter.)
Basically, I’mgoing to performpage flipped animation,in which one page (that is, a
bitmap large enough to hold a full screen) of display memory is displayed while
another page is drawn to. When the drawing is finished, thenewly modified page is
displayed, and the other-now invisible-page is drawn to. The process repeats ad
infinitum. For further information, some good places to start areComputer Guphics,
by Foley and van Dam (Addison-Wesley);Principles oflnteructive Computer Graphics,by
Newman and Sproull (McGraw Hill) ; and “Real-TimeAnimation” by Rahner James
(January 1990, Dr. Dobb’s Journal ) .
Some of the code inthis chapter was adapted forMode X from the codein Chapter
44-yet another reason to read that chapter before finishing this one.
924 Chapter 49
background page. (See the discussion in the previous chapter for the display memory
organization used by Listing 49.5.)So far as the displayed image is concerned, there
is never any hint of flicker or disturbance of the [Link] continues at a rate
of up to 60 times a second until Esc is pressed to exit the program. See Figure 49.1
for ascreen shot of the resulting image-add the animation inyour imagination.
#define SCREEN-SEG
OxAOOO
#define SCREEN-WIDTH 320
#define SCREEN-HEIGHT 240
#define PAGEO-START-OFFSET 0
#define PAGE1-START-OFFSET (((long)SCREEN-HEIGHT*SCREEN-WIOTH)/4)
#define BG-STARTLOFFSET (((long)SCREEN_HEIGHT*SCREEN_WIDTH*2)/4)
#define DOWNLOAD-STARTLOFFSET (((long)SCREENKHEIGHT*SCREEN-WIDTH*3)/4)
-
-
-
s t a t i cu n s i g n e di n tP a g e S t a r t O f f s e t s C Z l
s t a t i cc h a rG r e e n A n d B r o w n P a t t e r n C ]
s t a t i cc h a rP i n e T r e e P a t t e r n C l
{[Link]-START-OFFSET):
( 2 . 6 . 2 . 6 .6 . 2 . 6 . 2 .2 . 6 . 2 . 6 .6 . 2 . 6 . 2 ) ;
([Link], 2 . 6 . 2 . 6 .2 . 2 . 6 . 2 . 2.2.2,2):
- I 6 . 6 . 7 . 6 .7 . 7 . 7 . 7 .7 . 6 . 6 , 6 . 7.7,7,7.}:
-
s t a t i cc h a rB r i c k P a t t e r n C l
s t a t i cc h a rR o o f P a t t e r n C l ( 8 . 8 . 8 . 7 , 7 . 7 . 7 . 7 . 8 . 8 . 8 . 7 ,8 . 8 . 8 . 7 ) ;
# d e f i n e SMOKE-WIDTH 7
# d e f i n e SMOKE-HEIGHT 7
0. 7. [Link]. 0.
8. 7. 7. [Link],
8. 7. 7. 7. 7.15.15.
0. 8, 7. 7, 7. 7.15.
0. 0. 8. 7. 7. 7. 0.
0. 0. 0. 8. 8. 0. 01:
s t a t i cc h a r SmokeMaskCl
0. 0. 1. 1. 1. 0. 0.
- (
0. 1. 1. 1. 1. 1. 0.
1, 1, 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1. 1.
1, 1. 1. 1. 1. 1. 1.
[Link].1.1.0.
0. 0. 1. 1. 1. 0. 01:
# d e f i n e KITELWIDTH 10
# d e f i n e KITELHEIGHT 16
s t a t i cc h a rK i t e P i x e l s C l
0. 0. 0. 0.45, 0. 0. 0.
- 0. 0.
(
0. 0. [Link], 0. 0. 0. 0.
0. [Link].47.47. 0. 0. 0.
[Link],[Link]. 0. 0.
49.49,[Link].49.49.49. 0.
0,[Link].50.50.50. 0. 0.
[Link].51.51,51.51, 0. 0.
0. [Link].52.52. 0. 0. 0.
0. 0,[Link].53. 0. 0. 0.
0, 0, [Link]. 0. 0, 0. 0.
0. 0. [Link]. 0. 0. 0. 0.
0. 0. 0. 0.58, 0. 0. 0. 0. 0.
0. 0. 0. 0.59, 0. 0. 0. 0.66.
0. 0. 0. 0.60, 0. 0.64, 0.65.
0. 0. 0. 0. 0.61, 0. 0.64. 0.
0. 0. 0. 0. 0. 0.62.63, 0.641;
s t a t i cc h a rK i t e M a s k C l
[Link],[Link].0.0.
- (
0. 0. 0. 1. 1. 1. 0. 0, 0. 0.
0. 0. 1. 1. 1. 1. 1. 0. 0. 0.
0. 1. 1. 1. 1. 1. 1. 1. 0. 0.
1. 1. 1. 1. 1. 1. 1. 1. 1. 0.
[Link].[Link].0.0.
0. 1. 1. 1. 1. 1. 1. 1. 0. 0.
0. 0. 1. 1, 1. 1. 1. 0. 0. 0,
0. 0. 1. 1. 1. 1. 1. 0. 0. 0.
[Link].[Link],0.0.
0. 0. 0. 1. 1. 1. 0. 0. 0. 0.
[Link].[Link],0.0.
0. 0. 0. 0. 1. 0. 0. 0. 0. 1.
0. 0. 0. 0. 1. 0. 0. 1. 0. 1.
0. 0. 0. 0. 0. 1. 0. 0. 1. 0.
0. 0. 0. 0. 0. 0. 1. 1. 0. 11:
s t a t i c MaskedImageKiteImage:
# d e f i n e NUM-OBJECTS 20
t y p e d e fs t r u c t (
i n t X,[Link];
MaskedImage*Image:
1 Animatedobject:
926 Chapter 49
A n i m a t e d o b j e c tA n i m a t e d O b j e c t s C l-I
[ 0. [Link]-WIDTH.KITE_HEIGHT. 1. 1. 0. O , & K i t e I m a g e l ,
{ 1 0 . 10,[Link]-HEIGHT. 0 . 1, 1 0l.O . & K i t e I m a g e I .
{ 20. [Link].-1. 1, 20.2O.&KiteImagej.
[ 30. [Link]~[Link]~HEIGHT."1. 3 0 3. 0 . & K i t e I m a g e j ,
( 40. [Link]-HEIGHT. 1;l. 40.40.&KiteImage).
[ 50, [Link],KITEKHEIGHT. O,-l 50.
, 50.&KiteImage).
I 6 0 , [Link]-WIDTH.KITE_HEIGHT. 1. 0. 60.60.&KiteImage).
[ 70. [Link]-HEIGHT,-l, 0 . 70.7D.&KiteImage).
[ EO. [Link]-HEIGHT. 1, 2. EO. EO,&KiteImage).
{ 90. [Link]-HEIGHT. 0. 2.90,90.&KiteImage}.
[[Link]~[Link]~HEIGHT.-1. 2.100.10D.&KiteImageI.
~[Link].-1.-2,llO,llO.&KiteIma~e~.
[ 1 2 0 . 1 2 0 . K I T E ~ W I D T H , K I T E ~ H E I G H T , 1.-2.120.120.&KiteImage).
[130.130,KITEKWIDTH,KITEKHE1GHT, 0.-2.130.130.&KiteImage).
([Link]~[Link]. 2,0.140.140.&KiteImage).
{150.150,KITE~WIDTH.KITEKHE1GHT,-2. 0.150,150.&KiteImage).
(160,160,KITEKWIDTH.K1TEKHE1GHT, 2.2,16D.l60.&KiteImage),
{[Link]~[Link]~HEIGHT.-2, 2.170.170.&KiteImage).
{1E0.1E0,KITEKWIOTH,KITEKHEIGHT.-2.-2,lEO,lEO,&KiteImage~,
[190.190,KITE~WIDTH,KITEKHEIGHT, 2.-2.190.190.&KiteImagej.
I;
voidmain(void);
v o i dD r a w B a c k g r o u n d ( u n s i g n e di n t ) ;
v o i d MoveObject(Animated0bject * ) ;
e x t e r nv o i dS e t 3 2 0 ~ 2 4 0 M o d e ( v o i d ) ;
e x t e r nv o i dF i l l R e c t a n g l e X ( i n t ,i n t .i n t .i n t .u n s i g n e di n t .i n t ) :
e x t e r nv o i dF i l l P a t t e r n X ( i n t .i n t .i n t .i n t .u n s i g n e di n t .c h a r * ) ;
e x t e r nv o i d CopySystemToScreenMaskedX(int. i n t . i n t . i n t , i n t . i n t .
c h a r *, u n s i g n e di n t .i n t .i n t ,c h a r *);
e x t e r nv o i d CopyScreenToScreenX(int. i n t . i n t . i n t . i n t . i n t ,
u n s i g n e di n t .u n s i g n e di n t .i n t .i n t ) ;
e x t e r nu n s i g n e di n t CreateAlignedMaskedImage(Masked1mage * ,
u n s i g n e di n t .c h a r *, i n t .i n t .c h a r *):
e x t e r nv o i d CopyScreenToScreenMaskedX(int. i n t . i n t . i n t . i n t . i n t .
MaskedImage *, u n s i g n e d i n t . i n t ) ;
e x t e r nv o i dS h o w P a g e ( u n s i g n e di n t ) ;
voidmain0
I
i nD
t i s p l a y e d P a g eN . o n D i s p l a y e d P a g eD , one, i;
u n i o n REGS r e g s e t ;
Set320x240ModeO;
/ * D o w n l o a dt h ek i t ei m a g ef o rf a s tc o p y i n gl a t e r . */
i f (CreateAlignedMaskedImage(&KiteImage. DOWNLOADKSTART-OFFSET,
K i t e P i x e l s . KITELWIDTH. KITELHEIGHT, KiteMask) --
-
0) {
[Link] 0 x 0 0 0 3 ;i n t E 6 ( 0 x 1 0 .& r e g s e t .& r e g s e t ) :
p r i n t f ( " C o u 1 d n ' tg e tm e m o r y \ n " ) :e x i t ( ) ;
j
/* Draw t h eb a c k g r o u n dt ot h eb a c k g r o u n dp a g e . */
DrawBackground(BG-STARTL0FFSET);
/ * Copy t h eb a c k g r o u n dt ob o t hd i s p l a y a b l ep a g e s . */
CopyScreenToScreenX(0, 0 . SCREEN-WIDTH, SCREENKHEIGHT. 00. .
BG-START-OFFSET, PAGEO-START-OFFSET, SCREEN-WIDTH. SCREENKWIDTH);
CopyScreenToScreenX(0, 0. SCREENKWIDTH. SCREEN-HEIGHT. 0.0.
BGKSTART-OFFSET. PAGE1-START-OFFSET, SCREEN-WIDTH. SCREEN-WIDTH);
/ * Move t h eo b j e c t sa n du p d a t et h e i ri m a g e si nt h en o n d i s p l a y e d
f l i p t h e page, u n t i l Esc i s p r e s s e d . * /
-
p a g e t, h e n
Done = D i s p l a y e d P a g e 0;
do I
NonDisplayedPage -D i s p l a y e d P a g e A 1;
1
if (getch0 -
OxlB)Done 1; -
I* Esc t o end * I
1 w h i l e( ! D o n e ) :
I* R e s t o r e t e x t mode anddone.
- 0 x 0 0 0 3 ;i n t 8 6 ( 0 x 1 0 .
*I
[Link] & r e g s e t .& r e g s e t ) ;
1
voidDrawBackground(unsigned i n tP a g e s t a r t )
I
i n ti . j , T e m p ;
I* F i l lt h es c r e e nw i t hc y a n . *I
F i l l R e c t a n g l e X ( 0 , 0. SCREEN-WIDTH. SCREEN-HEIGHT. P a g e s t a r t . 11);
I* Draw a g r e e na n db r o w nr e c t a n g l et oc r e a t e a f l a t p l a i n . *I
F i l l P a t t e r n X ( 0 1. 6 0 , SCREEN-WIDTH, SCREEN-HEIGHT. PageStart,
GreenAndBrownPattern):
I* D r a wb l u ew a t e ra tt h eb o t t o mo ft h es c r e e n . *I
F i l l R e c t a n g l e X ( 0 . SCREENLHEIGHT-30. SCREEN-WIDTH. SCREEN-HEIGHT.
P a g e s t a r t , 1) :
I* Draw a b r o w n m o u n t a i n r i s i n g o u t o f t h e p l a i n . *I
f o r( i - 0 :i < 1 2 0 : i++)
FillRectangleX(SCREEN~WIDTHl2-30-i. 51+i, SCREEN-WIDTH/2-30+i+l,
5 1 + i + lP, a g e s t a r t6. ) ;
I* Draw a y e l l o ws u nb yo v e r l a p p i n gr e c t so fv a r i o u ss h a p e s . *I
Temp -
f o r( i - 0 i; < - 2 0 : i++) (
(int)(sqrt(20.0*20.0 - ( f l o a t ) i * ( f l o a t ) i ) + 0.5):
F i l l R e c t a n g l e X ( S C R E E N _ W I D T H - 2 5 - i . 30-Temp,
SCREEN-WIDTH-25+i+l.
30+Temp+l. P a g e s t a r t 1. 4 ) ;
1
I* D r a wg r e e nt r e e s down t h e s i d e o ft h em o u n t a i n . *I
f o r( i - 1 0 :i < 9 0 ; i +- 1 5 )
f o r( j - 0 ;j < 2 0 ; j++)
FillPatternX(SCREENLWIDTH12+i-j13-15, i + j + 5 1 , S C R E E N ~ W I D T H / 2 + i + j I 3 - 1 5 + 1 ,
i + j + 5 1 + 1P. a g e s t a r tP. i n e T r e e P a t t e r n ) :
I* Draw a house on t h e p l a i n . *I
F i l l P a t t e r n X ( 2 6 5 1. 5 0 2. 9 5 1. 7 0 P
. a g e s t a r tB
. rickPattern);
928 Chapter 49
F i l l P a t t e r n X ( 2 6 51, 3 02. 7 01, 5 0P. a g e S t a r tB. r i c k P a t t e r n ) ;
f o r( i = O :i < 1 2 ; i++)
F i l l P a t t e r n X ( 2 8 0 - i * 2 1. 3 8 + i . 2 8 O + i * 2 + 11. 3 8 + i + lP. a g e s t a r tR. o o f P a t t e r n ) :
/ * F i n a l l y ,d r a wp u f f so f smoke r i s i n gf r o mt h ec h i m n e y . *I
f o r( i - 0 :i < 4 ; i++)
CopySystemToScreenMaskedX(0, 0 . SMOKELWIDTH. SMOKE-HEIGHT. 264,
1 1 0 - i * 2 0S, m o k e P i x e l sP. a g e S t a r t . SMOKE-WIDTH.SCREEN_WIDTH, SmokeMask):
1
/* Move t h e s p e c i f i e d o b j e c t , b o u n c i n g a t t h e e d g e s o f t h es c r e e na n d
r e m e m b e r i n gw h e r et h eo b j e c t was b e f o r e t h e move f o r e r a s i n g n e x t t i m e . *I
v o i d MoveObject(Animated0bject * ObjectToMove)
-
i n t X, Y:
ObjectToMove->X + ObjectToMove->XDir;
-
X
Y ObjectToMove->Y + ObjectToMove->YDir:
i f ( ( X < 0 ) 1 1 (X > (SCREEN-WIDTH - O b j e c t T o M o v e - > W i d t h ) ) ) [
X -
ObjectToMove->XDir - -0bjectToMove->XDir:
ObjectToMove->X + ObjectToMove->XDir:
1
if ((Y < 0 ) 1 1 ( Y > (SCREEN-HEIGHT - O b j e c t T o M o v e - > H e i g h t ) ) ) {
ObjectToMove->YDir -
-0bjectToMove->YDir:
Y -
ObjectToMove->Y + ObjectToMove->YDir;
1
/ * Remember p r e v i o u sl o c a t i o nf o re r a s i n gp u r p o s e s .
-
*I
ObjectToMove->XDtherPage ObjectToMove->X:
ObjectToMove->YOtherPage ObjectToMove->Y; -
ObjectToMove->X -
X : / * s e t new l o c a t i o n * /
ObjectToMove->Y Y: -
1
LISTING [Link]
: Shows t h e p a g e a t t h e s p e c i f i e d o f f s e t i n t h e b i t m a p . Page i s d i s p l a y e d when
: t h i sr o u t i n er e t u r n s .
: C n e a r - c a l l a b l ea s :v o i dS h o w P a g e ( u n s i g n e di n tS t a r t o f f s e t ) :
INPUTLSTATUSLl 0e3q:duI naSpht ua t u s 1 register
CRTC-INDEX equ 03d4h :CRT C or enI gnt rdoel lxe r
START-ADDRESS-HIGH equ Och ; b i t sm atdadrptbhr eyi gst ehs
START_ADDRESSLLOWequ Odh : basiydttltdm
aoerrw
aetps s
ShowPageParms struc
dw 2 dup ( ? ) :pushed BP and r e t ua rdnd r e s s
Startoffset dw ? d i s ptpol abygioet: fm
oi fnaf ps e t
ShowPageParms
ends
.model
small
.code
p u b l3i ch o w P a g e
-Showpage n e aprr o c
push bp : p r e s e r v ec a l l e r ’ ss t a c kf r a m e
mov [Link] ; p o i n tt ol o c a ls t a c kf r a m e
: W a i tf o rd i s p l a ye n a b l et ob ea c t i v e( s t a t u si sa c t i v el o w ) .t ob e
: s u r eb o t hh a l v e so ft h es t a r ta d d r e s s will t a k e i n t h e same frame.
[Link]-ADDRESS-LOW
mov : p r e l o a df o rf a s t e s t
mov [Link] yp tt era r t O f f s e t C b p ] : f l i p p i n g o n c ed i s p l a y
cl.START_ADDRESS-HIGH
mov : e n a b l e i sd e t e c t e d
mov c h . b ySpttera r t O f f s e t + l [ b p ]
mov [Link]-STATUSpl
WaitDE:
in a1 .dx
test
- active)
a1 ,Olh
jnz WaitDE ; d i s p l a ye n a b l ei sa c t i v el o w (0
: Setthestartoffsetindisplay memory o f t h e page t o d i s p l a y .
[Link]
mov
mov [Link]
;start [Link] out
mov ax,cx
;start [Link] out
: Now w a i t f o r v e r t i c a l s y n c , s o t h eo t h e rp a g e will b e i n v i s i b l e when
: we s t a r t d r a w i n g t o i t .
mov [Link]-STATUS-1
Wai tVS:
in ,dx a1
test a1 .08h
jz WaitVS : v e r t i c a ls y n ci sa c t i v eh i g h (1 - active)
POP bp : r e s t o r ec a l l e r ’ ss t a c kf r a m e
ret
endp -Showpage
end
930 Chapter 49