368 lines
17 KiB
HTML
368 lines
17 KiB
HTML
<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: 10,000 Freshly Sheared Sheep on the Screen</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=57//-->
|
|
<!--PAGES=1069-1073//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="57-02.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="57-04.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<P><B>LISTING 57.2 L57-2.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; Draws all pixels in the specified scan line, with the pixel colors
|
|
; taken from the specified texture map. Uses approach of pre-stepping
|
|
; 1/2 pixel into the source image and rounding to the nearest source
|
|
; pixel at each step, so that texture maps will appear reasonably similar
|
|
; at all angles. This routine is specific to 320-pixel-wide planar
|
|
; (non-chain4) 256-color modes, such as mode X, which is a planar
|
|
; (non-chain4) 256-color mode with a resolution of 320x240.
|
|
; C near-callable as:
|
|
; void ScanOutLine(EdgeScan * LeftEdge, EdgeScan * RightEdge);
|
|
; Tested with TASM 3.0.
|
|
|
|
SC-INDEX equ 03c4h ;Sequence Controller Index
|
|
MAP-MASK equ 02h ;index in SC of Map Mask register
|
|
SCREEN-SEG equ 0a000h ;segment of display memory in mode X
|
|
SCREEN-WIDTH equ 80 ;width of screen in bytes from one scan line
|
|
; to the next
|
|
|
|
.model small
|
|
.data
|
|
extrn -TexMapBits:word, -TexMapWidth:word, -DestY:word
|
|
extrn -CurrentPageBase:word, -ClipMinX:word
|
|
extrn -ClipMinY:word, -ClipMaxX:word, -ClipMaxY:word
|
|
|
|
; Describes the current location and stepping, in both the source and
|
|
; the destination, of an edge. Mirrors structure in DRAWTEXP.C.
|
|
EdgeScan struc
|
|
Direction dw ? ;through edge list; 1 for a right edge (forward
|
|
; through vertex list), -1 for a left edge (backward
|
|
; through vertex list)
|
|
RemainingScans dw ? ;height left to scan out in dest
|
|
CurrentEnd dw ? ;vertex # of end of current edge
|
|
SourceX dd ? ;X location in source for this edge
|
|
SourceY dd ? ;Y location in source for this edge
|
|
SourceStepX dd ? ;X step in source for Y step in dest of 1
|
|
SourceStepY dd ? ;Y step in source for Y step in dest of 1
|
|
;variables used for all-integer Bresenham’s-type
|
|
; X stepping through the dest, needed for precise
|
|
; pixel placement to avoid gaps
|
|
DestX dw ? ;current X location in dest for this edge
|
|
DestXIntStep dw ? ;whole part of dest X step per scan-line Y step
|
|
DestXDirection dw ? ;-1 or 1 to indicate which way X steps (left/right)
|
|
DestXErrTerm dw ? ;current error term for dest X stepping
|
|
DestXAdjUp dw ? ;amount to add to error term per scan line move
|
|
DestXAdjDown dw ? ;amount to subtract from error term when the
|
|
; error term turns over
|
|
EdgeScan ends
|
|
|
|
Parms struc
|
|
dw 2 dup(?) ;return address & pushed BP
|
|
LeftEdge dw ? ;pointer to EdgeScan structure for left edge
|
|
RightEdge dw ? ;pointer to EdgeScan structure for right edge
|
|
Parms ends
|
|
|
|
;Offsets from BP in stack frame of local variables.
|
|
lSourceX equ -4 ;current X coordinate in source image
|
|
lSourceY equ -8 ;current Y coordinate in source image
|
|
lSourceStepX equ -12 ;X step in source image for X dest step of 1
|
|
lSourceStepY equ -16 ;Y step in source image for X dest step of 1
|
|
lXAdvanceByOne equ -18 ;used to step source pointer 1 pixel
|
|
; incrementally in X
|
|
lXBaseAdvance equ -20 ;use to step source pointer minimum number of
|
|
; pixels incrementally in X
|
|
lYAdvanceByOne equ -22 ;used to step source pointer 1 pixel
|
|
; incrementally in Y
|
|
lYBaseAdvance equ -24 ;use to step source pointer minimum number of
|
|
; pixels incrementally in Y
|
|
LOCAL-SIZE equ 24 ;total size of local variables
|
|
.code
|
|
extrn -FixedMul:near, -FixedDiv:near
|
|
align 2
|
|
ToScanDone:
|
|
jmp ScanDone
|
|
public -ScanOutLine
|
|
align 2
|
|
-ScanOutLine proc near
|
|
push bp ;preserve caller’s stack frame
|
|
mov bp,sp ;point to our stack frame
|
|
sub sp,LOCAL-SIZE ;allocate space for local variables
|
|
push si ;preserve caller’s register variables
|
|
push di
|
|
; Nothing to do if destination is fully X clipped.
|
|
mov di,[bp].RightEdge
|
|
mov si,[di].DestX
|
|
cmp si,[-ClipMinX]
|
|
jle ToScanDone ;right edge is to left of clip rect, so done
|
|
mov bx,[bp].LeftEdge
|
|
mov dx,[bx].DestX
|
|
cmp dx,[-ClipMaxX]
|
|
jge ToScanDone ;left edge is to right of clip rect, so done
|
|
sub si,dx ;destination fill width
|
|
jle ToScanDone ;null or negative full width, so done
|
|
|
|
mov ax,word ptr [bx].SourceX ;initial source X coordinate
|
|
mov word ptr [bp].lSourceX,ax
|
|
mov ax,word ptr [bx].SourceX+2
|
|
mov word ptr [bp].lSourceX+2,ax
|
|
|
|
mov ax,word ptr [bx].SourceY ;initial source Y coordinate
|
|
mov word ptr [bp].lSourceY,ax
|
|
mov ax,word ptr [bx].SourceY+2
|
|
mov word ptr [bp].lSourceY+2,ax
|
|
; Calculate source steps that correspond to each 1-pixel destination X step
|
|
; (across the destination scan line).
|
|
push si ;push dest X width, in fixedpoint form
|
|
sub ax,ax
|
|
push ax ;push 0 as fractional part of dest X width
|
|
mov ax,word ptr [di].SourceX
|
|
sub ax,word ptr [bp].lSourceX ;low word of source X width
|
|
mov dx,word ptr [di].SourceX+2
|
|
sbb dx,word ptr [bp].lSourceX+2 ;high word of source X width
|
|
push dx ;push source X width, in fixedpoint form
|
|
push ax
|
|
call -FixedDiv ;scale source X width to dest X width
|
|
add sp,8 ;clear parameters from stack
|
|
mov word ptr [bp].lSourceStepX,ax ;remember source X step for
|
|
mov word ptr [bp].lSourceStepX+2,dx ; 1-pixel destination X step
|
|
mov cx,1 ;assume source X advances non-negative
|
|
and dx,dx ;which way does source X advance?
|
|
jns SourceXNonNeg ;non-negative
|
|
neg cx ;negative
|
|
cmp ax,0 ;is the whole step exactly an integer?
|
|
jz SourceXNonNeg ;yes
|
|
inc dx ;no, truncate to integer in the direction of
|
|
; 0, because otherwise we’ll end up with a
|
|
; whole step of 1-too-large magnitude
|
|
SourceXNonNeg:
|
|
mov [bp].lXAdvanceByOne,cx ;amount to add to source pointer to
|
|
; move by one in X
|
|
mov [bp].lXBaseAdvance,dx ;minimum amount to add to source
|
|
; pointer to advance in X each time
|
|
; the dest advances one in X
|
|
push si ;push dest Y height, in fixedpoint form
|
|
sub ax,ax
|
|
push ax ;push 0 as fractional part of dest Y height
|
|
mov ax,word ptr [di].SourceY
|
|
sub ax,word ptr [bp].lSourceY ;low word of source Y height
|
|
mov dx,word ptr [di].SourceY+2
|
|
sbb dx,word ptr [bp].lSourceY+2 ;high word of source Y height
|
|
push dx ;push source Y height, in fixedpoint form
|
|
push ax
|
|
call -FixedDiv ;scale source Y height to dest X width
|
|
add sp,8 ;clear parameters from stack
|
|
mov word ptr [bp].lSourceStepY,ax ;remember source Y step for
|
|
mov word ptr [bp].lSourceStepY+2,dx ; 1-pixel destination X step
|
|
mov cx,[-TexMapWidth] ;assume source Y advances non-negative
|
|
and dx,dx ;which way does source Y advance?
|
|
jns SourceYNonNeg ;non-negative
|
|
neg cx ;negative
|
|
cmp ax,0 ;is the whole step exactly an integer?
|
|
jz SourceYNonNeg ;yes
|
|
inc dx ;no, truncate to integer in the direction of
|
|
; 0, because otherwise we’ll end up with a
|
|
; whole step of 1-too-large magnitude
|
|
SourceYNonNeg:
|
|
mov [bp].lYAdvanceByOne,cx ;amount to add to source pointer to
|
|
; move by one in Y
|
|
mov ax,[-TexMapWidth] ;minimum distance skipped in source
|
|
imul dx ; image bitmap when Y steps (ignoring
|
|
mov [bp].lYBaseAdvance,ax ; carry from the fractional part)
|
|
; Advance 1/2 step in the stepping direction, to space scanned pixels evenly
|
|
; between the left and right edges. (There’s a slight inaccuracy in dividing
|
|
; negative numbers by 2 by shifting rather than dividing, but the inaccuracy
|
|
; is in the least significant bit, and we’ll just live with it.)
|
|
mov ax,word ptr [bp].lSourceStepX
|
|
mov dx,word ptr [bp].lSourceStepX+2
|
|
sar dx,1
|
|
rcr ax,1
|
|
add word ptr [bp].lSourceX,ax
|
|
adc word ptr [bp].lSourceX+2,dx
|
|
|
|
mov ax,word ptr [bp].lSourceStepY
|
|
mov dx,word ptr [bp].lSourceStepY+2
|
|
sar dx,1
|
|
rcr ax,1
|
|
add word ptr [bp].lSourceY,ax
|
|
adc word ptr [bp].lSourceY+2,dx
|
|
; Clip right edge if necessary.
|
|
mov si,[di].DestX
|
|
cmp si,[-ClipMaxX]
|
|
jl RightEdgeClipped
|
|
mov si,[-ClipMaxX]
|
|
RightEdgeClipped:
|
|
; Clip left edge if necssary
|
|
mov bx,[bp].LeftEdge
|
|
mov di,[bx].DestX
|
|
cmp di,[-ClipMinX]
|
|
jge LeftEdgeClipped
|
|
; Left clipping is necessary; advance the source accordingly
|
|
neg di
|
|
add di,[-ClipMinX] ;ClipMinX - DestX
|
|
;first, advance the source in X
|
|
push di ;push ClipMinX - DestX, in fixedpoint form
|
|
sub ax,ax
|
|
push ax ;push 0 as fractional part of ClipMinX-DestX
|
|
push word ptr [bp].lSourceStepX+2
|
|
push word ptr [bp].lSourceStepX
|
|
call -FixedMul ;total source X stepping in clipped area
|
|
add sp,8 ;clear parameters from stack
|
|
add word ptr [bp].lSourceX,ax;step the source X past clipping
|
|
adc word ptr [bp].lSourceX+2,dx
|
|
;now advance the source in Y
|
|
push di ;push ClipMinX - DestX, in fixedpoint form
|
|
sub ax,ax
|
|
push ax ;push 0 as fractional part of ClipMinX-DestX
|
|
push word ptr [bp].lSourceStepY+2
|
|
push word ptr [bp].lSourceStepY
|
|
call -FixedMul ;total source Y stepping in clipped area
|
|
add sp,8 ;clear parameters from stack
|
|
add word ptr [bp].lSourceY,ax;step the source Y past clipping
|
|
adc word ptr [bp].lSourceY+2,dx
|
|
mov di,[-ClipMinX] ;start X coordinate in dest after clipping
|
|
LeftEdgeClipped:
|
|
; Calculate actual clipped destination drawing width.
|
|
sub si,di
|
|
; Scan across the destination scan line, updating the source image position
|
|
; accordingly.
|
|
; Point to the initial source image pixel, adding 0.5 to both X and Y so that
|
|
; we can truncate to integers from now on but effectively get rounding.
|
|
add word ptr [bp].lSourceY,8000h;add 0.5
|
|
mov ax,word ptr [bp].lSourceY+2
|
|
adc ax,0
|
|
mul [-TexMapWidth] ;initial scan line in source image
|
|
add word ptr [bp].lSourceX,8000h;add 0.5
|
|
mov bx,word ptr [bp].lSourceX+2 ;offset into source scan line
|
|
adc bx,ax ;initial source offset in source image
|
|
add bx,[-TexMapBits] ;DS:BX points to the initial image pixel
|
|
; Point to initial destination pixel.
|
|
mov ax,SCREEN-SEG
|
|
mov es,ax
|
|
mov ax,SCREEN-WIDTH
|
|
mul [-DestY] ;offset of initial dest scan line
|
|
mov cx,di ;initial destination X
|
|
shr di,1
|
|
shr di,1 ;X/4 = offset of pixel in scan line
|
|
add di,ax ;offset of pixel in page
|
|
add di,[-CurrentPageBase] ;offset of pixel in display memory
|
|
;ES:DI now points to the first destination pixel
|
|
|
|
and cl,011b ;CL = pixel’s plane
|
|
mov al,MAP-MASK
|
|
mov dx,SC-INDEX
|
|
out dx,al ;point the SC Index register to the Map Mask
|
|
mov al,11h ;one plane bit in each nibble, so we’ll get carry
|
|
; automatically when going from plane 3 to plane 0
|
|
shl al,cl ;set the bit for the first pixel’s plane to 1
|
|
; If source X step is negative, change over to working with non-negative
|
|
; values.
|
|
cmp word ptr [bp].lXAdvanceByOne,0
|
|
jge SXStepSet
|
|
neg word ptr [bp].lSourceStepX
|
|
not word ptr [bp].lSourceX
|
|
SXStepSet:
|
|
; If source Y step is negative, change over to working with non-negative
|
|
; values.
|
|
cmp word ptr [bp].lYAdvanceByOne,0
|
|
jge SYStepSet
|
|
neg word ptr [bp].lSourceStepY
|
|
not word ptr [bp].lSourceY
|
|
SYStepSet:
|
|
; At this point:
|
|
; AL = initial pixel’s plane mask
|
|
; BX = pointer to initial image pixel
|
|
; SI = # of pixels to fill
|
|
; DI = pointer to initial destination pixel
|
|
mov dx,SC-INDEX+1 ;point to SC Data; Index points to Map Mask
|
|
TexScanLoop:
|
|
; Set the Map Mask for this pixel’s plane, then draw the pixel.
|
|
out dx,al
|
|
mov ah,[bx] ;get image pixel
|
|
mov es:[di],ah ;set image pixel
|
|
; Point to the next source pixel.
|
|
add bx,[bp].lXBaseAdvance ;advance the minimum # of pixels in X
|
|
mov cx,word ptr [bp].lSourceStepX
|
|
add word ptr [bp].lSourceX,cx;step the source X fractional part
|
|
jnc NoExtraXAdvance ;didn’t turn over; no extra advance
|
|
add bx,[bp].lXAdvanceByOne ;did turn over; advance X one extra
|
|
NoExtraXAdvance:
|
|
add bx,[bp].lYBaseAdvance;advance the minimum # of pixels in Y
|
|
mov cx,word ptr [bp].lSourceStepY
|
|
add word ptr [bp].lSourceY,cx;step the source Y fractional part
|
|
jnc NoExtraYAdvance;didn’t turn over; no extra advance
|
|
add bx,[bp].lYAdvanceByOne;did turn over; advance Y one extra
|
|
NoExtraYAdvance:
|
|
; Point to the next destination pixel, by cycling to the next plane, and
|
|
; advancing to the next address if the plane wraps from 3 to 0.
|
|
rol al,1
|
|
adc di,0
|
|
; Continue if there are any more dest pixels to draw.
|
|
dec si
|
|
jnz TexScanLoop
|
|
ScanDone:
|
|
pop di ;restore caller’s register variables
|
|
pop si
|
|
mov sp,bp ;deallocate local variables
|
|
pop bp ;restore caller’s stack frame
|
|
ret
|
|
-ScanOutLine endp
|
|
end
|
|
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="57-02.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="57-04.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 -->
|
|
|
|
|