Initial scrape from http://www.phatcode.net/res/224/files/html/
This commit is contained in:
commit
b946ff9e70
683 changed files with 62902 additions and 0 deletions
76
ch53/53-01.html
Normal file
76
ch53/53-01.html
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<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=989-992//-->
|
||||
<!--UNASSIGNED1//-->
|
||||
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
||||
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="../ch52/52-08.html">Previous</A></TD>
|
||||
<TD><A HREF="../index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="53-02.html">Next</A></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<P><BR></P>
|
||||
<H2><A NAME="Heading1"></A><FONT COLOR="#000077">Chapter 53<BR>Raw Speed and More
|
||||
</FONT></H2>
|
||||
<H3><A NAME="Heading2"></A><FONT COLOR="#000077">The Naked Truth About Speed in 3-D Animation</FONT></H3>
|
||||
<P>Years ago, this friend of mine—let’s call him Bert—went to Hawaii with three other fellows to celebrate their graduation from high school. This was an unchaperoned trip, and they behaved pretty much as responsibly as you’d expect four teenagers to behave, which is to say, not; there’s a story about a rental car that, to this day, Bert can’t bring himself to tell. They had a good time, though, save for one thing: no girls.
|
||||
</P>
|
||||
<P>By and by, they met a group of girls by the pool, but the boys couldn’t get past the hi-howya-doin stage, so they retired to their hotel room to plot a better approach. This being the early ’70s, and them being slightly tipsy teenagers with raging hormones and the effective combined IQ of four eggplants, it took them no time at all to come up with a brilliant plan: streaking. The girls had mentioned their room number, so the boys piled into the elevator, pushed the button for the girls’ floor, shucked their clothes as fast as they could, and sprinted to the girls’ door. They knocked on the door and ran on down the hall. As the girls opened their door, Bert and his crew raced past, toward the elevator, laughing hysterically.</P>
|
||||
<P>Bert was by far the fastest of them all. He whisked between the elevator doors just as they started to close; by the time his friends got there, it was too late, and the doors slid shut in their faces. As the elevator began to move, Bert could hear the frantic pounding of six fists thudding on the closed doors. As Bert stood among the clothes littering the elevator floor, the thought of his friends stuck in the hall, naked as jaybirds, was just too much, and he doubled over with helpless laughter, tears streaming down his face. The universe had blessed him with one of those exceedingly rare moments of perfect timing and execution.</P>
|
||||
<P>The universe wasn’t done with Bert quite yet, though. He was still contorted with laughter—and still quite thoroughly undressed—when the elevator doors opened again. On the lobby.</P>
|
||||
<P>And with that, we come to this chapter’s topics: raw speed and hidden surfaces.</P>
|
||||
<H3><A NAME="Heading3"></A><FONT COLOR="#000077">Raw Speed, Part 1: Assembly Language</FONT></H3>
|
||||
<P>I would like to state, here and for the record, that I am not an assembly language fanatic. Frankly, I prefer programming in C; assembly language is hard work, and I can get a whole lot more done with fewer hassles in C. However, I <I>am</I> a performance fanatic, performance being defined as having programs be as nimble as possible in those areas where the user wants fast response. And, in the course of pursuing performance, there are times when a little assembly language goes a long way.</P>
|
||||
<P>We’re now four chapters into development of the X-Sharp 3-D animation package. In realtime animation, performance is <I>sine qua non</I> (Latin for “Make it fast or find another line of work”), so some judiciously applied assembly language is in order. In the previous chapter, we got up to a serviceable performance level by switching to fixed-point math, then implementing the fixed-point multiplication and division functions in assembly in order to take advantage of the 386’s 32-bit capabilities. There’s another area of the program that fairly cries out for assembly language: matrix math. The function to multiply a matrix by a vector (<B>XformVec()</B>) and the function to concatenate matrices (<B>ConcatXforms()</B>) both loop heavily around calls to <B>FixedMul();</B> a lot of calling and looping can be eliminated by converting these functions to pure assembly language.</P>
|
||||
<P>Listing 53.1 is the module FIXED.ASM from this chapter’s iteration of X-Sharp, with <B>XformVec()</B> and <B>ConcatXforms()</B> implemented in assembly language. The code is heavily optimized, to the extent of completely unrolling the loops via macros so that looping is eliminated altogether. FIXED.ASM is highly effective; the time taken for matrix math is now down to the point where it’s a fairly minor component of execution time, representing less than ten percent of the total. It’s time to turn our optimization sights elsewhere.</P><P><BR></P>
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="../ch52/52-08.html">Previous</A></TD>
|
||||
<TD><A HREF="../index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="53-02.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 -->
|
||||
|
||||
|
||||
456
ch53/53-02.html
Normal file
456
ch53/53-02.html
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
<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 -->
|
||||
|
||||
|
||||
77
ch53/53-03.html
Normal file
77
ch53/53-03.html
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<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=999-1001//-->
|
||||
<!--UNASSIGNED1//-->
|
||||
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
||||
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="53-02.html">Previous</A></TD>
|
||||
<TD><A HREF="../index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="53-04.html">Next</A></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<P><BR></P>
|
||||
<H3><A NAME="Heading4"></A><FONT COLOR="#000077">Raw Speed, Part II: Look it Up</FONT></H3>
|
||||
<P>It’s a funny thing about Turbo Profiler: Time spent in the Borland C<SMALL>++</SMALL> 80×87 emulator doesn’t show up directly anywhere that I can see in the timing results. The only way to detect it is by way of the line that reports what percent of total time is represented by all the areas that were profiled; if you’re profiling all areas, whatever’s not explicitly accounted for seems to be the floating-point emulator time. This quirk fooled me for a while, leading me to think sine and cosine weren’t major drags on performance, because the <B>sin()</B> and <B>cos()</B> functions spend most of their time in the emulator, and that time doesn’t show up in Turbo Profiler’s statistics on those functions. Once I figured out what was going on, it turned out that not only were <B>sin()</B> and <B>cos()</B> major drags, they were taking up over half the total execution time by themselves.</P>
|
||||
<P>The solution is a lookup table. Listing 53.1 contains a function called <B>CosSin()</B> that calculates both the sine and cosine of an angle, via a lookup table. The function accepts angles in tenths of degrees; I decided to use tenths of degrees rather than radians because that way it’s always possible to look up the sine and cosine of the exact angle requested, rather than approximating, as would be required with radians. Tenths of degrees should be fine enough control for most purposes; if not, it’s easy to alter <B>CosSin()</B> for finer gradations yet. GENCOS.C, the program used to generate the lookup table (COSTABLE.INC), included in Listing 53.1, can be found in the XSHARP22 subdirectory on the listings diskette. GENCOS.C can generate a cosine table with any integral number of steps per degree.</P>
|
||||
<P>FIXED.ASM (Listing 53.1) speeds X-Sharp up quite a bit, and it changes the performance balance a great deal. When we started out with 3-D animation, calculation time was the dragon we faced; more than 90 percent of the total time was spent doing matrix and projection math. Additional optimizations in the area of math could still be made (using 32-bit multiplies in the backface-removal code, for example), but fixed-point math, the sine and cosine lookup, and selective assembly optimizations have done a pretty good job already. The bulk of the time taken by X-Sharp is now spent drawing polygons, drawing rectangles (to erase objects), and waiting for the page to flip. In other words, we’ve slain the dragon of 3-D math, or at least wounded it grievously; now we’re back to the dragon of polygon filling. We’ll address faster polygon filling soon, but for the moment, we have more than enough horsepower to have some fun with. First, though, we need one more feature: hidden surfaces.</P>
|
||||
<H4 ALIGN="LEFT"><A NAME="Heading5"></A><FONT COLOR="#000077">Hidden Surfaces</FONT></H4>
|
||||
<P>So far, we’ve made a number of simplifying assumptions in order to get the animation to look good; for example, all objects must currently be convex polyhedrons. What’s more, right now, objects can never pass behind or in front of each other. What that means is that it’s time to have a look at hidden surfaces.
|
||||
</P>
|
||||
<P>There are a passel of ways to do hidden surfaces. Way off at one end (the slow end) of the spectrum is Z-buffering, whereby each pixel of each polygon is checked as it’s drawn to see whether it’s the frontmost version of the pixel at those coordinates. At the other end is the technique of simply drawing the objects in back-to-front order, so that nearer objects are drawn on top of farther objects. The latter approach, depth sorting, is the one we’ll take today. (Actually, true depth sorting involves detecting and resolving possible ambiguities when objects overlap in Z; in this chapter, we’ll simply sort the objects on Z and leave it at that.)</P>
|
||||
<P>This limited version of depth sorting is fast but less than perfect. For one thing, it doesn’t address the issue of nonconvex objects, so we’ll have to stick with convex polyhedrons. For another, there’s the question of what part of each object to use as the sorting key; the nearest point, the center, and the farthest point are all possibilities—and, whichever point is used, depth sorting doesn’t handle some overlap cases properly. Figure 53.1 illustrates one case in which back-to-front sorting doesn’t work, regardless of what point is used as the sorting key.</P>
|
||||
<P>For photo-realistic rendering, these are serious problems. For fast PC-based animation, however, they’re manageable. Choose objects that aren’t too elongated; arrange their paths of travel so they don’t intersect in problematic ways; and, if they do overlap incorrectly, trust that the glitch will be lost in the speed of the animation and the complexity of the screen.</P>
|
||||
<P>Listing 53.2 shows X-Sharp file OLIST.C, which includes the key routines for depth sorting. Objects are now stored in a linked list. The initial, empty list, created by <B>InitializeObjectList(),</B> consists of a sentinel entry at either end, one at the farthest possible z coordinate, and one at the nearest. New entries are inserted by <B>AddObject()</B> in z-sorted order. Each time the objects are moved, before they’re drawn at their new locations, <B>SortObjects()</B> is called to Z-sort the object list, so that drawing will proceed from back to front. The Z-sorting is done on the basis of the objects’ center points; a center-point field has been added to the object structure to support this, and the center point for each object is now transformed along with the vertices. That’s really all there is to depth sorting—and now we can have objects that overlap in X and Y.</P>
|
||||
<P><A NAME="Fig1"><!-- </A><A HREF="javascript:displayWindow('images/53-01.jpg',407,199 )"> --><IMG SRC="images/53-01.jpg"><BR><!-- </A>
|
||||
<BR><A HREF="javascript:displayWindow('images/53-01.jpg',407,199)"> --><FONT COLOR="#000077"><B>Figure 53.1</B></FONT></A> <I>Why back-to-front sorting doesn’t always work properly.</I>
|
||||
<P><BR></P>
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="53-02.html">Previous</A></TD>
|
||||
<TD><A HREF="../index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="53-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 -->
|
||||
|
||||
|
||||
156
ch53/53-04.html
Normal file
156
ch53/53-04.html
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
<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=1001-1003//-->
|
||||
<!--UNASSIGNED1//-->
|
||||
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
||||
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="53-03.html">Previous</A></TD>
|
||||
<TD><A HREF="../index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="../ch54/54-01.html">Next</A></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<P><BR></P>
|
||||
</P>
|
||||
<P><B>LISTING 53.2 OLIST.C</B></P>
|
||||
<!-- CODE //-->
|
||||
<PRE>
|
||||
/* Object list-related functions. */
|
||||
#include <stdio.h>
|
||||
#include “polygon.h”
|
||||
|
||||
/* Set up the empty object list, with sentinels at both ends to
|
||||
terminate searches */
|
||||
void InitializeObjectList()
|
||||
{
|
||||
ObjectListStart.NextObject = &ObjectListEnd;
|
||||
ObjectListStart.PreviousObject = NULL;
|
||||
ObjectListStart.CenterInView.Z = INT-TO-FIXED(-32768);
|
||||
ObjectListEnd.NextObject = NULL;
|
||||
ObjectListEnd.PreviousObject = &ObjectListStart;
|
||||
ObjectListEnd.CenterInView.Z = 0x7FFFFFFFL;
|
||||
NumObjects = 0;
|
||||
}
|
||||
|
||||
/* Adds an object to the object list, sorted by center Z coord. */
|
||||
void AddObject(Object *ObjectPtr)
|
||||
{
|
||||
Object *ObjectListPtr = ObjectListStart.NextObject;
|
||||
|
||||
/* Find the insertion point. Guaranteed to terminate because of
|
||||
the end sentinel */
|
||||
while (ObjectPtr->CenterInView.Z > ObjectListPtr->CenterInView.Z) {
|
||||
ObjectListPtr = ObjectListPtr->NextObject;
|
||||
}
|
||||
|
||||
/* Link in the new object */
|
||||
ObjectListPtr->PreviousObject->NextObject = ObjectPtr;
|
||||
ObjectPtr->NextObject = ObjectListPtr;
|
||||
ObjectPtr->PreviousObject = ObjectListPtr->PreviousObject;
|
||||
ObjectListPtr->PreviousObject = ObjectPtr;
|
||||
NumObjects++;
|
||||
}
|
||||
|
||||
/* Resorts the objects in order of ascending center Z coordinate in view space,
|
||||
by moving each object in turn to the correct position in the object list. */
|
||||
void SortObjects()
|
||||
{
|
||||
int i;
|
||||
Object *ObjectPtr, *ObjectCmpPtr, *NextObjectPtr;
|
||||
|
||||
/* Start checking with the second object */
|
||||
ObjectCmpPtr = ObjectListStart.NextObject;
|
||||
ObjectPtr = ObjectCmpPtr->NextObject;
|
||||
for (i=1; i<NumObjects; i++) {
|
||||
/* See if we need to move backward through the list */
|
||||
if (ObjectPtr->CenterInView.Z < ObjectCmpPtr->CenterInView.Z) {
|
||||
/* Remember where to resume sorting with the next object */
|
||||
NextObjectPtr = ObjectPtr->NextObject;
|
||||
/* Yes, move backward until we find the proper insertion
|
||||
point. Termination guaranteed because of start sentinel */
|
||||
do {
|
||||
ObjectCmpPtr = ObjectCmpPtr->PreviousObject;
|
||||
} while (ObjectPtr->CenterInView.Z <
|
||||
ObjectCmpPtr->CenterInView.Z);
|
||||
|
||||
/* Now move the object to its new location */
|
||||
/* Unlink the object at the old location */
|
||||
ObjectPtr->PreviousObject->NextObject =
|
||||
ObjectPtr->NextObject;
|
||||
ObjectPtr->NextObject->PreviousObject =
|
||||
ObjectPtr->PreviousObject;
|
||||
|
||||
/* Link in the object at the new location */
|
||||
ObjectCmpPtr->NextObject->PreviousObject = ObjectPtr;
|
||||
ObjectPtr->PreviousObject = ObjectCmpPtr;
|
||||
ObjectPtr->NextObject = ObjectCmpPtr->NextObject;
|
||||
ObjectCmpPtr->NextObject = ObjectPtr;
|
||||
|
||||
/* Advance to the next object to sort */
|
||||
ObjectCmpPtr = NextObjectPtr->PreviousObject;
|
||||
ObjectPtr = NextObjectPtr;
|
||||
} else {
|
||||
/* Advance to the next object to sort */
|
||||
ObjectCmpPtr = ObjectPtr;
|
||||
ObjectPtr = ObjectPtr->NextObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
</PRE>
|
||||
<!-- END CODE //-->
|
||||
<H4 ALIGN="LEFT"><A NAME="Heading6"></A><FONT COLOR="#000077">Rounding</FONT></H4>
|
||||
<P>FIXED.ASM contains the equate <B>ROUNDING-ON</B>. When this equate is 1, the results of multiplications and divisions are rounded to the nearest fixed-point values; when it’s 0, the results are truncated. The difference between the results produced by the two approaches is, at most, 2<SUP><SMALL>-16</SMALL></SUP>; you wouldn’t think that would make much difference, now, would you? But it does. When the animation is run with rounding disabled, the cubes start to distort visibly after a few minutes, and after a few minutes more they look like they’ve been run over. In contrast, I’ve never seen any significant distortion with rounding on, even after a half-hour or so. I think the difference with rounding is not that it’s so much more accurate, but rather that the errors are evenly distributed; with truncation, the errors are biased, and biased errors become very visible when they’re applied to right-angle objects. Even with rounding, though, the errors will eventually creep in, and reorthogonalization will become necessary at some point.</P>
|
||||
<P>The performance cost of rounding is small, and the benefits are highly visible. Still, truncation errors become significant only when they accumulate over time, as, for example, when rotation matrices are repeatedly concatenated over the course of many transformations. Some time could be saved by rounding only in such cases. For example, division is performed only in the course of projection, and the results do not accumulate over time, so it would be reasonable to disable rounding for division. <H4 ALIGN="LEFT"><A NAME="Heading7"></A><FONT COLOR="#000077">Having a Ball</P>
|
||||
</FONT></H4>
|
||||
<P>So far in our exploration of 3-D animation, we’ve had nothing to look at but triangles and cubes. It’s time for something a little more visually appealing, so the demonstration program now features a 72-sided ball. What’s particularly interesting about this ball is that it’s created by the GENBALL.C program in the BALL subdirectory of X-Sharp, and both the size of the ball and the number of bands of faces are programmable. GENBALL.C spits out to a file all the arrays of vertices and faces needed to create the ball, ready for inclusion in INITBALL.C. True, if you change the number of bands, you must change the Colors array in INITBALL.C to match, but that’s a tiny detail; by and large, the process of generating a ball-shaped object is now automated. In fact, we’re not limited to ball-shaped objects; substitute a different vertex and face generation program for GENBALL.C, and you can make whatever convex polyhedron you want; again, all you have to do is change the <B>Colors</B> array correspondingly. You can easily create multiple versions of the base object, too; INITCUBE.C is an example of this, creating 11 different cubes.</P>
|
||||
<P>What we have here is the first glimmer of an object-editing system. GENBALL.C is the prototype for object definition, and INITBALL.C is the prototype for general-purpose object instantiation. Certainly, it would be nice to someday have an interactive 3-D object editing tool and resource management setup. We have our hands full with the drawing end of things at the moment, though, and for now it’s enough to be able to create objects in a semiautomated way.</P><P><BR></P>
|
||||
<CENTER>
|
||||
<TABLE BORDER>
|
||||
<TR>
|
||||
<TD><A HREF="53-03.html">Previous</A></TD>
|
||||
<TD><A HREF="../index.html">Table of Contents</A></TD>
|
||||
<TD><A HREF="../ch54/54-01.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 -->
|
||||
|
||||
|
||||
BIN
ch53/images/53-01.jpg
Normal file
BIN
ch53/images/53-01.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Loading…
Reference in a new issue