456 lines
17 KiB
HTML
456 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: Raw Speed and More</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=53//-->
|
|
<!--PAGES=992-999//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="53-01.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="53-03.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<P><B>LISTING 53.1 FIXED.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; 386-specific fixed point routines.
|
|
; Tested with TASM
|
|
ROUNDING-ON equ 1 ;1 for rounding, 0 for no rounding
|
|
;no rounding is faster, rounding is
|
|
; more accurate
|
|
ALIGNMENT equ 2
|
|
.model small
|
|
.386
|
|
.code
|
|
;=====================================================================
|
|
; Multiplies two fixed-point values together.
|
|
; C near-callable as:
|
|
; Fixedpoint FixedMul(Fixedpoint M1, Fixedpoint M2);
|
|
; Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
|
|
FMparms struc
|
|
dw 2 dup(?) ;return address & pushed BP
|
|
M1 dd ?
|
|
M2 dd ?
|
|
FMparms ends
|
|
align ALIGNMENT
|
|
public -FixedMul
|
|
-FixedMul proc near
|
|
push bp
|
|
mov bp,sp
|
|
mov eax,[bp+M1]
|
|
imul dword ptr [bp+M2] ;multiply
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shr eax,16 ;put the fractional part in AX
|
|
pop bp
|
|
ret
|
|
-FixedMul endp
|
|
;=====================================================================
|
|
; Divides one fixed-point value by another.
|
|
; C near-callable as:
|
|
; Fixedpoint FixedDiv(Fixedpoint Dividend, Fixedpoint Divisor);
|
|
FDparms struc
|
|
dw 2 dup(?) ;return address & pushed BP
|
|
Dividend dd ?
|
|
Divisor dd ?
|
|
FDparms ends
|
|
align ALIGNMENT
|
|
public -FixedDiv
|
|
-FixedDiv proc near
|
|
push bp
|
|
mov bp,sp
|
|
|
|
if ROUNDING-ON
|
|
sub cx,cx ;assume positive result
|
|
mov eax,[bp+Dividend]
|
|
and eax,eax ;positive dividend?
|
|
jns FDP1 ;yes
|
|
inc cx ;mark it’s a negative dividend
|
|
neg eax ;make the dividend positive
|
|
FDP1: sub edx,edx ;make it a 64-bit dividend, then shift
|
|
; left 16 bits so that result will be
|
|
; in EAX
|
|
rol eax,16 ;put fractional part of dividend in
|
|
; high word of EAX
|
|
mov dx,ax ;put whole part of dividend in DX
|
|
sub ax,ax ;clear low word of EAX
|
|
mov ebx,dword ptr [bp+Divisor]
|
|
and ebx,ebx ;positive divisor?
|
|
jns FDP2 ;yes
|
|
dec cx ;mark it’s a negative divisor
|
|
neg ebx ;make divisor positive
|
|
FDP2: div ebx ;divide
|
|
shr ebx,1 ;divisor/2, minus 1 if the divisor is
|
|
adc ebx,0 ; even
|
|
dec ebx
|
|
cmp ebx,edx ;set Carry if remainder is at least
|
|
adc eax,0 ; half as large as the divisor, then
|
|
; use that to round up if necessary
|
|
and cx,cx ;should the result be made negative?
|
|
jz FDP3 ;no
|
|
neg eax ;yes, negate it
|
|
FDP3:
|
|
else ; !ROUNDING-ON
|
|
mov edx,[bp+Dividend]
|
|
sub eax,eax
|
|
shrd eax,edx,16 ;position so that result ends up
|
|
sar edx,16 ; in EAX
|
|
idivdword ptr [bp+Divisor]
|
|
endif ;ROUNDING-ON
|
|
shld edx,eax,16 ;whole part of result in DX;
|
|
; fractional part is already in AX
|
|
pop bp
|
|
ret
|
|
-FixedDiv endp
|
|
;=====================================================================
|
|
; Returns the sine and cosine of an angle.
|
|
; C near-callable as:
|
|
;void CosSin(TAngle Angle, Fixedpoint *Cos, Fixedpoint *);
|
|
|
|
align ALIGNMENT
|
|
CosTable label dword
|
|
include costable.inc
|
|
|
|
SCparms struc
|
|
dw 2 dup(?) ;return address & pushed BP
|
|
Angle dw ? ;angle to calculate sine & cosine for
|
|
Cos dw ? ;pointer to cos destination
|
|
Sin dw ? ;pointer to sin destination
|
|
SCparms ends
|
|
|
|
align ALIGNMENT
|
|
public -CosSin
|
|
-CosSinprocnear
|
|
push bp ;preserve stack frame
|
|
mov bp,sp ;set up local stack frame
|
|
|
|
mov bx,[bp].Angle
|
|
and bx,bx ;make sure angle’s between 0 and 2*pi
|
|
jns CheckInRange
|
|
MakePos:;less than 0, so make it positive
|
|
add bx,360*10
|
|
js MakePos
|
|
jmp short CheckInRange
|
|
|
|
align ALIGNMENT
|
|
MakeInRange: ;make sure angle is no more than 2*pi
|
|
sub bx,360*10
|
|
CheckInRange:
|
|
cmp bx,360*10
|
|
jg MakeInRange
|
|
|
|
cmp bx,180*10 ;figure out which quadrant
|
|
ja BottomHalf ;quadrant 2 or 3
|
|
cmp bx,90*10 ;quadrant 0 or 1
|
|
ja Quadrant1
|
|
;quadrant 0
|
|
shl bx,2
|
|
move ax,CosTable[bx] ;look up sine
|
|
neg bx ;sin(Angle) = cos(90-Angle)
|
|
move dx,CosTable[bx+90*10*4] ;look up cosine
|
|
jmp short CSDone
|
|
|
|
align ALIGNMENT
|
|
Quadrant1:
|
|
neg bx
|
|
add bx,180*10 ;convert to angle between 0 and 90
|
|
shl bx,2
|
|
mov eax,CosTable[bx] ;look up cosine
|
|
neg eax ;negative in this quadrant
|
|
neg bx ;sin(Angle) = cos(90-Angle)
|
|
move dx,CosTable[bx+90*10*4] ;look up cosine
|
|
jmp short CSDone
|
|
|
|
align ALIGNMENT
|
|
BottomHalf: ;quadrant 2 or 3
|
|
neg bx
|
|
add bx,360*10 ;convert to angle between 0 and 180
|
|
cmp bx,90*10 ;quadrant 2 or 3
|
|
ja Quadrant2
|
|
;quadrant 3
|
|
shl bx, 2
|
|
mov eax,CosTable[bx] ;look up cosine
|
|
neg bx ;sin(Angle) = cos(90-Angle)
|
|
movedx,CosTable[90*10*4+bx] ;look up sine
|
|
nege dx ;negative in this quadrant
|
|
jmp short CSDone
|
|
|
|
align ALIGNMENT
|
|
Quadrant2:
|
|
neg bx
|
|
add bx,180*10 ;convert to angle between 0 and 90
|
|
shl bx,2
|
|
mov eax,CosTable[bx] ;look up cosine
|
|
neg eax ;negative in this quadrant
|
|
neg bx ;sin(Angle) = cos(90-Angle)
|
|
move dx,CosTable[90*10*4+bx] ;look up sine
|
|
nege dx ;negative in this quadrant
|
|
CSDone:
|
|
mov bx,[bp].Cos
|
|
mov [bx],eax
|
|
mov bx,[bp].Sin
|
|
mov [bx],edx
|
|
|
|
pop bp;restore stack frame
|
|
ret
|
|
-CosSinendp
|
|
;=====================================================================
|
|
; Matrix multiplies Xform by SourceVec, and stores the result in
|
|
; DestVec. Multiplies a 4x4 matrix times a 4x1 matrix; the result
|
|
; is a 4x1 matrix. Cheats by assuming the W coord is 1 and the
|
|
; bottom row of the matrix is 0 0 0 1, and doesn’t bother to set
|
|
; the W coordinate of the destination.
|
|
; C near-callable as:
|
|
; void XformVec(Xform WorkingXform, Fixedpoint *SourceVec,
|
|
; Fixedpoint *DestVec);
|
|
;
|
|
; This assembly code is equivalent to this C code:
|
|
; int i;
|
|
;
|
|
; for (i=0; i<3; i++)
|
|
; DestVec[i] = FixedMul(WorkingXform[i][0], SourceVec[0]) +
|
|
; FixedMul(WorkingXform[i][1], SourceVec[1]) +
|
|
; FixedMul(WorkingXform[i][2], SourceVec[2]) +
|
|
; WorkingXform[i][3]; /* no need to multiply by W = 1 */
|
|
|
|
XVparms struc
|
|
dw 2 dup(?) ;return address & pushed BP
|
|
WorkingXform dw ? ;pointer to transform matrix
|
|
SourceVec dw ? ;pointer to source vector
|
|
DestVec dw ? ;pointer to destination vector
|
|
XVparms ends
|
|
|
|
align ALIGNMENT
|
|
public -XformVec
|
|
-XformVec proc near
|
|
push bp ;preserve stack frame
|
|
mov bp,sp ;set up local stack frame
|
|
push si ;preserve register variables
|
|
push di
|
|
|
|
mov si,[bp].WorkingXform ;SI points to xform matrix
|
|
mov bx,[bp].SourceVec ;BX points to source vector
|
|
mov di,[bp].DestVec ;DI points to dest vector
|
|
|
|
soff=0
|
|
doff=0
|
|
REPT 3 ;do once each for dest X, Y, and Z
|
|
mov eax,[si+soff] ;column 0 entry on this row
|
|
imul dword ptr [bx] ;xform entry times source X entry
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16;shift the result back to 16.16 form
|
|
mov ecx,eax ;set running total
|
|
|
|
mov eax,[si+soff+4] ;column 1 entry on this row
|
|
imul dword ptr [bx+4] ;xform entry times source Y entry
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
add ecx,eax ;running total for this row
|
|
|
|
mov eax,[si+soff+8] ;column 2 entry on this row
|
|
imul dword ptr [bx+8] ;xform entry times source Z entry
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
add ecx,eax ;running total for this row
|
|
|
|
add ecx,[si+soff+12] ;add in translation
|
|
mov[di+doff],ecx ;save the result in the dest vector
|
|
soff=soff+16
|
|
doff=doff+4
|
|
ENDM
|
|
|
|
popdi;restore register variables
|
|
popsi
|
|
popbp;restore stack frame
|
|
ret
|
|
-XformVecendp
|
|
;=====================================================================
|
|
; Matrix multiplies SourceXform1 by SourceXform2 and stores the
|
|
; result in DestXform. Multiplies a 4x4 matrix times a 4x4 matrix;
|
|
; the result is a 4x4 matrix. Cheats by assuming the bottom row of
|
|
; each matrix is 0 0 0 1, and doesn’t bother to set the bottom row
|
|
; of the destination.
|
|
; C near-callable as:
|
|
; void ConcatXforms(Xform SourceXform1, Xform SourceXform2,
|
|
; Xform DestXform)
|
|
;
|
|
; This assembly code is equivalent to this C code:
|
|
; int i, j;
|
|
;
|
|
; for (i=0; i<3; i++) {
|
|
; for (j=0; j<3; j++)
|
|
; DestXform[i][j] =
|
|
; FixedMul(SourceXform1[i][0], SourceXform2[0][j]) +
|
|
; FixedMul(SourceXform1[i][1], SourceXform2[1][j]) +
|
|
; FixedMul(SourceXform1[i][2], SourceXform2[2][j]);
|
|
; DestXform[i][3] =
|
|
; FixedMul(SourceXform1[i][0], SourceXform2[0][3]) +
|
|
; FixedMul(SourceXform1[i][1], SourceXform2[1][3]) +
|
|
; FixedMul(SourceXform1[i][2], SourceXform2[2][3]) +
|
|
; SourceXform1[i][3];
|
|
; }
|
|
|
|
CXparms struc
|
|
dw 2 dup(?) ;return address & pushed BP
|
|
SourceXform1 dw ? ;pointer to first source xform matrix
|
|
SourceXform2 dw ? ;pointer to second source xform matrix
|
|
DestXform dw ? ;pointer to destination xform matrix
|
|
CXparms ends
|
|
|
|
align ALIGNMENT
|
|
public -ConcatXforms
|
|
-ConcatXforms proc near
|
|
push bp ;preserve stack frame
|
|
mov bp,sp ;set up local stack frame
|
|
push si ;preserve register variables
|
|
pushdi
|
|
|
|
mov bx,[bp].SourceXform2 ;BX points to xform2 matrix
|
|
mov si,[bp].SourceXform1 ;SI points to xform1 matrix
|
|
mov di,[bp].DestXform ;DI points to dest xform matrix
|
|
|
|
roff=0 ;row offset
|
|
REPT 3 ;once for each row
|
|
coff=0 ;column offset
|
|
REPT 3 ;once for each of the first 3 columns,
|
|
; assuming 0 as the bottom entry (no
|
|
; translation)
|
|
mov eax,[si+roff] ;column 0 entry on this row
|
|
imul dword ptr [bx+coff];times row 0 entry in column
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adcedx,0;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
mov ecx,eax ;set running total
|
|
|
|
mov eax,[si+roff+4] ;column 1 entry on this row
|
|
imul dword ptr [bx+coff+16];times row 1 entry in col
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
add ecx,eax ;running total
|
|
|
|
mov eax,[si+roff+8] ;column 2 entry on this row
|
|
imul dword ptr [bx+coff+32];times row 2 entry in col
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
add ecx,eax ;running total
|
|
|
|
mov[di+coff+roff],ecx ;save the result in dest matrix
|
|
coff=coff+4 ;point to next col in xform2 & dest
|
|
ENDM
|
|
;now do the fourth column, assuming
|
|
; 1 as the bottom entry, causing
|
|
; translation to be performed
|
|
mov eax,[si+roff] ;column 0 entry on this row
|
|
imul dword ptr [bx+coff] ;times row 0 entry in column
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
mov ecx,eax ;set running total
|
|
|
|
mov eax,[si+roff+4] ;column 1 entry on this row
|
|
imul dword ptr [bx+coff+16];times row 1 entry in col
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
add ecx,eax ;running total
|
|
|
|
mov eax,[si+roff+8] ;column 2 entry on this row
|
|
imul dword ptr [bx+coff+32];times row 2 entry in col
|
|
if ROUNDING-ON
|
|
add eax,8000h ;round by adding 2^(-17)
|
|
adc edx,0 ;whole part of result is in DX
|
|
endif ;ROUNDING-ON
|
|
shrd eax,edx,16 ;shift the result back to 16.16 form
|
|
addecx,eax;running total
|
|
|
|
addecx,[si+roff+12];add in translation
|
|
|
|
mov[di+coff+roff],ecx;save the result in dest matrix
|
|
coff=coff+4 ;point to next col in xform2 & dest
|
|
|
|
roff=roff+16 ;point to next col in xform2 & dest
|
|
ENDM
|
|
|
|
popdi;restore register variables
|
|
popsi
|
|
popbp;restore stack frame
|
|
ret
|
|
-ConcatXformsendp
|
|
end
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="53-01.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="53-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 -->
|
|
|
|
|