home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Programming Black Book (Special Edition)
/
BlackBook.bin
/
disk1
/
source
/
chapterc
/
lc-4.asm
< prev
next >
Wrap
Assembly Source File
|
1997-06-18
|
17KB
|
354 lines
; *** Listing 18.4 ***
;
; Contains 3 C-callable routines: GenerateOctant, DrawVOctant, and
; DrawHOctant. See individual routines for comments.
;
; Assembled with TASM 4.0. Link with L18-2.C and L18-3.C.
; Checked by Jim Mischel 11/30/94.
;
ISVGA equ 0 ;set to 1 to use VGA write mode 3
; keep synchronized with Listing 3
.model small
.code
;********************************************************************
; Generates an octant of the specified circle, placing the results in
; PixList, with a 0 in PixList meaning draw pixel & move only along
; major axis, and a 1 in PixList meaning draw pixel & move along both
; axes.
; C near-callable as:
; int GenerateOctant(unsigned char *PixList, int MajorAxis,
; int MinorAxis, unsigned long RadiusSqMinusMajorAxisSq,
; unsigned long MinorAxisSquaredThreshold);
;
; Return value = MajorAxis
;
GenerateOctantParms struc
dw ? ;pushed BP
dw ? ;return address
PixList dw ? ;pointer to list to store draw control data in
MajorAxis dw ? ;initial major/minor axis coords relative to
MinorAxis dw ? ; to the center of the circle
RadiusSqMinusMajorAxisSq dd ? ;initial Radius**2 - MajorAxis**2
MinorAxisSquaredThreshold dd ? ;initial threshhold for minor axis
GenerateOctantParms ends ; movement is MinorAxis**2 - MinorAxis
;
public _GenerateOctant
_GenerateOctant proc near
push bp ;preserve caller's stack frame
mov bp,sp ;point to our stack frame
push si ;preserve C register variables
push di
; ;get all parms into registers
mov di,[PixList+bp] ;point DI to PixList
mov ax,[MajorAxis+bp] ;AX=MajorAxis
mov bx,[MinorAxis+bp] ;BX=MinorAxis
mov cx,word ptr [RadiusSqMinusMajorAxisSq+bp]
mov dx,word ptr [RadiusSqMinusMajorAxisSq+bp+2]
;DX:CX=RadiusSqMinusMajorAxisSq
mov si,word ptr [MinorAxisSquaredThreshold+bp]
mov bp,word ptr [MinorAxisSquaredThreshold+bp+2]
;BP:SI=MinorAxisSquaredThreshold
GenLoop:
sub cx,1 ;subtract MajorAxis + MajorAxis + 1 from
sbb dx,0 ; RadiusSqMinusMajorAxisSq
sub cx,ax
sbb dx,0
sub cx,ax
sbb dx,0
cmp dx,bp ;if RadiusSqMinusMajorAxisSq <=
jb IsMinorMove ; MinorAxisSquaredThreshold, move along
ja NoMinorMove ; minor as well as major, otherwise move
cmp cx,si ; only along major
ja NoMinorMove
IsMinorMove: ;move along minor as well as major
dec bx ;decrement MinorAxis
sub si,bx ;subtract MinorAxis + MinorAxis from
sbb bp,0 ; MinorAxisSquaredThreshold
sub si,bx
sbb bp,0
mov byte ptr [di],1 ;enter 1 (move both axes) in PixList
inc di ;advance PixList pointer
inc ax ;increment MajorAxis
cmp ax,bx ;done if MajorAxis > MinorAxis, else
jbe GenLoop ; continue generating PixList entries
jmp short Done
NoMinorMove:
mov byte ptr [di],0 ;enter 0 (move only major) in PixList
inc di ;advance PixList pointer
inc ax ;increment MajorAxis
cmp ax,bx ;done if MajorAxis > MinorAxis, else
jbe GenLoop ; continue generating PixList entries
Done:
pop di ;restore C register variables
pop si
pop bp
ret
_GenerateOctant endp
;********************************************************************
; Draws the arc for an octant in which Y is the major axis. (X,Y) is the
; starting point of the arc. HorizontalMoveDirection selects whether the
; arc advances to the left or right horizontally (0=left, 1=right).
; RowOffset contains the offset in bytes from one scan line to the next,
; controlling whether the arc is drawn up or down. DrawLength is the
; vertical length in pixels of the arc, and DrawList is a list
; containing 0 for each point if the next point is vertically aligned,
; and 1 if the next point is 1 pixel diagonally to the left or right.
;
; The Graphics Controller Index register must already point to the Bit
; Mask register.
;
; C near-callable as:
; void DrawVOctant(int X, int Y, int DrawLength, int RowOffset,
; int HorizontalMoveDirection, unsigned char *DrawList);
;
DrawParms struc
dw ? ;pushed BP
dw ? ;return address
X dw ? ;initial coordinates
Y dw ?
DrawLength dw ? ;vertical length
RowOffset dw ? ;distance from one scan line to the next
HorizontalMoveDirection dw ? ;1 to move right, 0 to move left
DrawList dw ? ;pointer to list containing 1 to draw
DrawParms ends ; diagonally, 0 to draw vertically for
; each point
SCREEN_SEGMENT equ 0a000h ;display memory segment in mode 12h
SCREEN_WIDTH_IN_BYTES equ 80 ;distance from one scan line to next
GC_INDEX equ 3ceh ;GC Index register address
;
public _DrawVOctant
_DrawVOctant proc near
push bp ;preserve caller's stack frame
mov bp,sp ;point to our stack frame
push si ;preserve C register variables
push di
;Point ES:DI to the byte the initial pixel is in.
mov ax,SCREEN_SEGMENT
mov es,ax
mov ax,SCREEN_WIDTH_IN_BYTES
mul [bp+Y] ;Y*SCREEN_WIDTH_IN_BYTES
mov di,[bp+X] ;X
mov cx,di ;set X aside in CX
shr di,1
shr di,1
shr di,1 ;X/8
add di,ax ;screen offset = Y*SCREEN_WIDTH_IN_BYTES+X/8
and cl,07h ;X modulo 8
if ISVGA ;---VGA---
mov ah,80h ;keep VGA bit mask in AH
shr ah,cl ;initial bit mask = 80h shr (X modulo 8);
cld ;for LODSB, used below
else ;---EGA---
mov al,80h ;keep EGA bit mask in AL
shr al,cl ;initial bit mask = 80h shr (X modulo 8);
mov dx,GC_INDEX+1 ;point DX to GC Data reg/bit mask
endif ;---------
mov si,[bp+DrawList] ;SI points to list to draw from
sub bx,bx ;so we have the constant 0 in a reg
mov cx,[bp+DrawLength] ;CX=# of pixels to draw
jcxz VDrawDone ;skip this if no pixels to draw
cmp [bp+HorizontalMoveDirection],0 ;draw right or left
mov bp,[bp+RowOffset] ;BP=offset to next row
jz VGoLeft ;draw from right to left
VDrawRightLoop: ;draw from left to right
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3,
; set/reset provides color
lodsb ;get next draw control byte
and al,al ;move right?
jz VAdvanceOneLineRight ;no move right
ror ah,1 ;move right
else ;---EGA---
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter (set/reset provides
; color); just force read then write
cmp [si],bl ;check draw control byte; move right?
jz VAdvanceOneLineRight ;no move right
ror al,1 ;move right
endif ;---------
adc di,bx ;move one byte to the right if mask wrapped
VAdvanceOneLineRight:
ife ISVGA ;---EGA---
inc si ;advance draw control list pointer
endif ;---------
add di,bp ;move to the next scan line up or down
loop VDrawRightLoop ;do next pixel, if any
jmp short VDrawDone ;done
VGoLeft: ;draw from right to left
VDrawLeftLoop:
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3
lodsb ;get next draw control byte
and al,al ;move left?
jz VAdvanceOneLineLeft ;no move left
rol ah,1 ;move left
else ;---EGA---
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter; force read/write
cmp [si],bl ;check draw control byte; move left?
jz VAdvanceOneLineLeft ;no move left
rol al,1 ;move left
endif ;---------
sbb di,bx ;move one byte to the left if mask wrapped
VAdvanceOneLineLeft:
ife ISVGA ;---EGA---
inc si ;advance draw control list pointer
endif ;---------
add di,bp ;move to the next scan line up or down
loop VDrawLeftLoop ;do next pixel, if any
VDrawDone:
pop di ;restore C register variables
pop si
pop bp
ret
_DrawVOctant endp
;********************************************************************
; Draws the arc for an octant in which X is the major axis. (X,Y) is the
; starting point of the arc. HorizontalMoveDirection selects whether the
; arc advances to the left or right horizontally (0=left, 1=right).
; RowOffset contains the offset in bytes from one scan line to the next,
; controlling whether the arc is drawn up or down. DrawLength is the
; horizontal length in pixels of the arc, and DrawList is a list
; containing 0 for each point if the next point is horizontally aligned,
; and 1 if the next point is 1 pixel above or below diagonally.
;
; Graphics Controller Index register must already point to the Bit Mask
; register.
;
; C near-callable as:
; void DrawHOctant(int X, int Y, int DrawLength, int RowOffset,
; int HorizontalMoveDirection, unsigned char *DrawList)
;
; Uses same parameter structure as DrawVOctant().
;
public _DrawHOctant
_DrawHOctant proc near
push bp ;preserve caller's stack frame
mov bp,sp ;point to our stack frame
push si ;preserve C register variables
push di
;Point ES:DI to the byte the initial pixel is in.
mov ax,SCREEN_SEGMENT
mov es,ax
mov ax,SCREEN_WIDTH_IN_BYTES
mul [bp+Y] ;Y*SCREEN_WIDTH_IN_BYTES
mov di,[bp+X] ;X
mov cx,di ;set X aside in CX
shr di,1
shr di,1
shr di,1 ;X/8
add di,ax ;screen offset = Y*SCREEN_WIDTH_IN_BYTES+X/8
and cl,07h ;X modulo 8
mov bh,80h
shr bh,cl ;initial bit mask = 80h shr (X modulo 8);
if ISVGA ;---VGA---
cld ;for LODSB, used below
else ;---EGA---
mov dx,GC_INDEX+1 ;point DX to GC Data reg/bit mask
endif ;---------
mov si,[bp+DrawList] ;SI points to list to draw from
sub bl,bl ;so we have the constant 0 in a reg
mov cx,[bp+DrawLength] ;CX=# of pixels to draw
jcxz HDrawDone ;skip this if no pixels to draw
if ISVGA ;---VGA---
sub ah,ah ;clear bit mask accumulator
else ;---EGA---
sub al,al ;clear bit mask accumulator
endif ;---------
cmp [bp+HorizontalMoveDirection],0 ;draw right or left
mov bp,[bp+RowOffset] ;BP=offset to next row
jz HGoLeft ;draw from right to left
HDrawRightLoop: ;draw from left to right
if ISVGA ;---VGA---
or ah,bh ;put this pixel in bit mask accumulator
lodsb ;get next draw control byte
and al,al ;move up/down?
else ;---EGA---
or al,bh ;put this pixel in bit mask accumulator
cmp [si],bl ;check draw control byte; move up/down?
endif ;---------
jz HAdvanceOneLineRight ;no move up/down
;move up/down; first draw accumulated pixels
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3
sub ah,ah ;clear bit mask accumulator
else ;---EGA---
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter; force read/write
sub al,al ;clear bit mask accumulator
endif ;---------
add di,bp ;move to the next scan line up or down
HAdvanceOneLineRight:
ife ISVGA ;---EGA---
inc si ;advance draw control list pointer
endif ;---------
ror bh,1 ;move to right; shift mask
jnc HDrawLoopRightBottom ;didn't wrap to the next byte
;move to next byte; 1st draw accumulated pixels
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3
sub ah,ah ;clear bit mask accumulator
else
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter; force read/write
sub al,al ;clear bit mask accumulator
endif ;---------
inc di ;move 1 byte to the right
HDrawLoopRightBottom:
loop HDrawRightLoop ;draw next pixel, if any
jmp short HDrawDone ;done
HGoLeft: ;draw from right to left
HDrawLeftLoop:
if ISVGA ;---VGA---
or ah,bh ;put this pixel in bit mask accumulator
lodsb ;get next draw control byte
and al,al ;move up/down?
else ;---EGA---
or al,bh ;put this pixel in bit mask accumulator
cmp [si],bl ;check draw control byte; move up/down?
endif ;---------
jz HAdvanceOneLineLeft ;no move up/down
;move up/down; first draw accumulated pixels
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3
sub ah,ah ;clear bit mask accumulator
else ;---EGA---
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter; force read/write
sub al,al ;clear bit mask accumulator
endif ;---------
add di,bp ;move to the next scan line up or down
HAdvanceOneLineLeft:
ife ISVGA ;---EGA---
inc si ;advance draw control list pointer
endif ;---------
rol bh,1 ;move to left; shift mask
jnc HDrawLoopLeftBottom ;didn't wrap to next byte
;move to next byte; 1st draw accumulated pixels
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3
sub ah,ah ;clear bit mask accumulator
else ;---EGA---
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter; force read/write
sub al,al ;clear bit mask accumulator
endif ;---------
dec di ;move 1 byte to the left
HDrawLoopLeftBottom:
loop HDrawLeftLoop ;draw next pixel, if any
HDrawDone:
;draw any remaining accumulated pixels
if ISVGA ;---VGA---
and es:[di],ah ;AH becomes bit mask in write mode 3
else ;---EGA---
out dx,al ;set the desired bit mask
and es:[di],al ;data doesn't matter; force read/write
endif ;---------
pop di ;restore C register variables
pop si
pop bp
ret
_DrawHOctant endp
end