abrash-black-book/18-03.html

564 lines
17 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<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: It's a Wonderful Life</title>
<meta name="chapter" content="18" />
<meta name="pages" content="352-361" />
</head>
<body>
<center>
<table border="1">
<tr>
<td>
<a href="18-02.html">Previous</a>
</td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td>
<a href="18-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><b>LISTING 18.1 BUILD.BAT</b></p>
<pre>
bcc -v -D%1=%2;%2=%3;%3=%4;%4=%5;%5=%6;%6=%7;%7=%8;%8 lcomp.c
lcomp &gt; qlife.asm
tasmx /mx /kh30000 qlife
bcc -v -D%1=%2;%2=%3;%3=%4;%4=%5;%5=%6;%6=%7;%7=%8;%8 qlife.obj main.c video.c
</pre>
<p><b>LISTING 18.2 LCOMP.C</b></p>
<pre>
// LCOMP.C
//
// Life compiler, ver 1.3
//
// David Stafford
//
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &ldquo;life.h&rdquo;
#define LIST_LIMIT (46 * 138) // when we need to use es:
int Old, New, Edge, Label;
char Buf[ 20 ];
void Next1( void )
{
char *Seg = &ldquo;&rdquo;;
if( WIDTH * HEIGHT &gt; LIST_LIMIT ) Seg = &ldquo;es:&rdquo;;
printf( &ldquo;mov bp,%s[si]\n&rdquo;, Seg );
printf( &ldquo;add si,2\n&rdquo; );
printf( &ldquo;mov dh,[bp+1]\n&rdquo; );
printf( &ldquo;and dh,0FEh\n&rdquo; );
printf( &ldquo;jmp dx\n&rdquo; );
}
void Next2( void )
{
printf( &ldquo;mov bp,es:[si]\n&rdquo; );
printf( &ldquo;add si,2\n&rdquo; );
printf( &ldquo;mov dh,[bp+1]\n&rdquo; );
printf( &ldquo;or dh,1\n&rdquo; );
printf( &ldquo;jmp dx\n&rdquo; );
}
void BuildMaps( void )
{
unsigned short i, j, Size, x = 0, y, N1, N2, N3, C1, C2, C3;
printf( &ldquo;_DATA segment &lsquo;DATA&rsquo;\nalign 2\n&rdquo; );
printf( &ldquo;public _CellMap\n&rdquo; );
printf( &ldquo;_CellMap label word\n&rdquo; );
for( j = 0; j &lt; HEIGHT; j++ )
{
for( i = 0; i &lt; WIDTH; i++ )
{
if( i == 0 || i == WIDTH-1 || j == 0 || j == HEIGHT-1 )
{
printf( &ldquo;dw 8000h\n&rdquo; );
}
else
{
printf( &ldquo;dw 0\n&rdquo; );
}
}
}
printf( &ldquo;ChangeCell dw 0\n&rdquo; );
printf( &ldquo;_RowColMap label word\n&rdquo; );
for( j = 0; j &lt; HEIGHT; j++ )
{
for( i = 0; i &lt; WIDTH; i++ )
{
printf( &ldquo;dw 0%02x%02xh\n&rdquo;, j, i * 3 );
}
}
if( WIDTH * HEIGHT &gt; LIST_LIMIT )
{
printf( &ldquo;Change1 dw offset _CHANGE:_ChangeList1\n&rdquo; );
printf( &ldquo;Change2 dw offset _CHANGE:_ChangeList2\n&rdquo; );
printf( &ldquo;ends\n\n&rdquo; );
printf( &ldquo;_CHANGE segment para public &lsquo;FAR_DATA&rsquo;\n&rdquo; );
}
else
{
printf( &ldquo;Change1 dw offset DGROUP:_ChangeList1\n&rdquo; );
printf( &ldquo;Change2 dw offset DGROUP:_ChangeList2\n&rdquo; );
}
Size = WIDTH * HEIGHT + 1;
printf( &ldquo;public _ChangeList1\n_ChangeList1 label word\n&rdquo; );
printf( &ldquo;dw %d dup (offset DGROUP:ChangeCell)\n&rdquo;, Size );
printf( &ldquo;public _ChangeList2\n_ChangeList2 label word\n&rdquo; );
printf( &ldquo;dw %d dup (offset DGROUP:ChangeCell)\n&rdquo;, Size );
printf( &ldquo;ends\n\n&rdquo; );
printf( &ldquo;_LDMAP segment para public &lsquo;FAR_DATA&rsquo;\n&rdquo; );
do
{
// Current cell states
C1 = (x &amp; 0x0800) &gt;&gt; 11;
C2 = (x &amp; 0x0400) &gt;&gt; 10;
C3 = (x &amp; 0x0200) &gt;&gt; 9;
// Neighbor counts
N1 = (x &amp; 0x01C0) &gt;&gt; 6;
N2 = (x &amp; 0x0038) &gt;&gt; 3;
N3 = (x &amp; 0x0007);
y = x &amp; 0x8FFF; // Preserve all but the next generation states
if( C1 &amp;&amp; ((N1 + C2 == 2) || (N1 + C2 == 3)) )
{
y |= 0x4000;
}
if( !C1 &amp;&amp; (N1 + C2 == 3) )
{
y |= 0x4000;
}
if( C2 &amp;&amp; ((N2 + C1 + C3 == 2) || (N2 + C1 + C3 == 3)) )
{
y |= 0x2000;
}
if( !C2 &amp;&amp; (N2 + C1 + C3 == 3) )
{
y |= 0x2000;
}
if( C3 &amp;&amp; ((N3 + C2 == 2) || (N3 + C2 == 3)) )
{
y |= 0x1000;
}
if( !C3 &amp;&amp; (N3 + C2 == 3) )
{
y |= 0x1000;
}
printf( &ldquo;db 0%02xh\n&rdquo;, y &gt;&gt; 8 );
}
while( ++x != 0 );
printf( &ldquo;ends\n\n&rdquo; );
}
void GetUpAndDown( void )
{
printf( &ldquo;mov ax,[bp+_RowColMap-_CellMap]\n&rdquo; );
printf( &ldquo;or ah,ah\n&rdquo; );
printf( &ldquo;mov dx,%d\n&rdquo;, DOWN );
printf( &ldquo;mov cx,%d\n&rdquo;, WRAPUP );
printf( &ldquo;jz short D%d\n&rdquo;, Label );
printf( &ldquo;cmp ah,%d\n&rdquo;, HEIGHT - 1 );
printf( &ldquo;mov cx,%d\n&rdquo;, UP );
printf( &ldquo;jb short D%d\n&rdquo;, Label );
printf( &ldquo;mov dx,%d\n&rdquo;, WRAPDOWN );
printf( &ldquo;D%d:\n&rdquo;, Label );
}
void FirstPass( void )
{
char *Op;
unsigned short UpDown = 0;
printf( &ldquo;org 0%02x00h\n&rdquo;, (Edge &lt;&lt; 7) + (New &lt;&lt; 4) + (Old &lt;&lt; 1) );
// reset cell
printf( &ldquo;xor byte ptr [bp+1],0%02xh\n&rdquo;, (New ^ Old) &lt;&lt; 1 );
// get the screen address and update the display
#ifndef NODRAW
printf( &ldquo;mov al,160\n&rdquo; );
printf( &ldquo;mov bx,[bp+_RowColMap-_CellMap]\n&rdquo; );
printf( &ldquo;mul bh\n&rdquo; );
printf( &ldquo;add ax,ax\n&rdquo; );
printf( &ldquo;mov bh,0\n&rdquo; );
printf( &ldquo;add bx,ax\n&rdquo; ); // bx = screen offset
if( ((New ^ Old) &amp; 6) == 6 )
{
printf( &ldquo;mov word ptr fs:[bx],0%02x%02xh\n&rdquo;,
(New &amp; 2) ? 15 : 0,
(New &amp; 4) ? 15 : 0 );
if( (New ^ Old) &amp; 1 )
{
printf( &ldquo;mov byte ptr fs:[bx+2],%s\n&rdquo;,
(New &amp; 1) ? &ldquo;15&rdquo; : &ldquo;dl&rdquo; );
}
}
else
{
if( ((New ^ Old) &amp; 3) == 3 )
{
printf( &ldquo;mov word ptr fs:[bx+1],0%02x%02xh\n&rdquo;,
(New &amp; 1) ? 15 : 0,
(New &amp; 2) ? 15 : 0 );
}
else
{
if( (New ^ Old) &amp; 2 )
{
printf( &ldquo;mov byte ptr fs:[bx+1],%s\n&rdquo;,
(New &amp; 2) ? &ldquo;15&rdquo; : &ldquo;dl&rdquo; );
}
if( (New ^ Old) &amp; 1 )
{
printf( &ldquo;mov byte ptr fs:[bx+2],%s\n&rdquo;,
(New &amp; 1) ? &ldquo;15&rdquo; : &ldquo;dl&rdquo; );
}
}
if( (New ^ Old) &amp; 4 )
{
printf( &ldquo;mov byte ptr fs:[bx],%s\n&rdquo;,
(New &amp; 4) ? &ldquo;15&rdquo; : &ldquo;dl&rdquo; );
}
}
#endif
if( (New ^ Old) &amp; 4 ) UpDown += (New &amp; 4) ? 0x48 : -0x48;
if( (New ^ Old) &amp; 2 ) UpDown += (New &amp; 2) ? 0x49 : -0x49;
if( (New ^ Old) &amp; 1 ) UpDown += (New &amp; 1) ? 0x09 : -0x09;
if( Edge )
{
GetUpAndDown(); // ah = row, al = col, cx = up, dx = down
if( (New ^ Old) &amp; 4 )
{
printf( &ldquo;mov di,%d\n&rdquo;, WRAPLEFT ); // di = left
printf( &ldquo;cmp al,0\n&rdquo; );
printf( &ldquo;je short L%d\n&rdquo;, Label );
printf( &ldquo;mov di,%d\n&rdquo;, LEFT );
printf( &ldquo;L%d:\n&rdquo;, Label );
if( New &amp; 4 ) Op = &ldquo;inc&rdquo;;
else Op = &ldquo;dec&rdquo;;
printf( &ldquo;%s word ptr [bp+di]\n&rdquo;, Op );
printf( &ldquo;add di,cx\n&rdquo; );
printf( &ldquo;%s word ptr [bp+di]\n&rdquo;, Op );
printf( &ldquo;sub di,cx\n&rdquo; );
printf( &ldquo;add di,dx\n&rdquo; );
printf( &ldquo;%s word ptr [bp+di]\n&rdquo;, Op );
}
if( (New ^ Old) &amp; 1 )
{
printf( &ldquo;mov di,%d\n&rdquo;, WRAPRIGHT ); // di = right
printf( &ldquo;cmp al,%d\n&rdquo;, (WIDTH - 1) * 3 );
printf( &ldquo;je short R%d\n&rdquo;, Label );
printf( &ldquo;mov di,%d\n&rdquo;, RIGHT );
printf( &ldquo;R%d:\n&rdquo;, Label );
if( New &amp; 1 ) Op = &ldquo;add&rdquo;;
else Op = &ldquo;sub&rdquo;;
printf( &ldquo;%s word ptr [bp+di],40h\n&rdquo;, Op );
printf( &ldquo;add di,cx\n&rdquo; );
printf( &ldquo;%s word ptr [bp+di],40h\n&rdquo;, Op );
printf( &ldquo;sub di,cx\n&rdquo; );
printf( &ldquo;add di,dx\n&rdquo; );
printf( &ldquo;%s word ptr [bp+di],40h\n&rdquo;, Op );
}
printf( &ldquo;mov di,cx\n&rdquo; );
printf( &ldquo;add word ptr [bp+di],%d\n&rdquo;, UpDown );
printf( &ldquo;mov di,dx\n&rdquo; );
printf( &ldquo;add word ptr [bp+di],%d\n&rdquo;, UpDown );
printf( &ldquo;mov dl,0\n&rdquo; );
}
else
{
if( (New ^ Old) &amp; 4 )
{
if( New &amp; 4 ) Op = &ldquo;inc&rdquo;;
else Op = &ldquo;dec&rdquo;;
printf( &ldquo;%s byte ptr [bp+%d]\n&rdquo;, Op, LEFT );
printf( &ldquo;%s byte ptr [bp+%d]\n&rdquo;, Op, UPPERLEFT );
printf( &ldquo;%s byte ptr [bp+%d]\n&rdquo;, Op, LOWERLEFT );
}
if( (New ^ Old) &amp; 1 )
{
if( New &amp; 1 ) Op = &ldquo;add&rdquo;;
else Op = &ldquo;sub&rdquo;;
printf( &ldquo;%s word ptr [bp+%d],40h\n&rdquo;, Op, RIGHT );
printf( &ldquo;%s word ptr [bp+%d],40h\n&rdquo;, Op, UPPERRIGHT );
printf( &ldquo;%s word ptr [bp+%d],40h\n&rdquo;, Op, LOWERRIGHT );
}
if( abs( UpDown ) &gt; 1 )
{
printf( &ldquo;add word ptr [bp+%d],%d\n&rdquo;, UP, UpDown );
printf( &ldquo;add word ptr [bp+%d],%d\n&rdquo;, DOWN, UpDown );
}
else
{
if( UpDown == 1 ) Op = &ldquo;inc&rdquo;;
else Op = &ldquo;dec&rdquo;;
printf( &ldquo;%s byte ptr [bp+%d]\n&rdquo;, Op, UP );
printf( &ldquo;%s byte ptr [bp+%d]\n&rdquo;, Op, DOWN );
}
}
Next1();
}
void Test( char *Offset, char *Str )
{
printf( &ldquo;mov bx,[bp+%s]\n&rdquo;, Offset );
printf( &ldquo;cmp bh,[bx]\n&rdquo; );
printf( &ldquo;jnz short FIX_%s%d\n&rdquo;, Str, Label );
printf( &ldquo;%s%d:\n&rdquo;, Str, Label );
}
void Fix( char *Offset, char *Str, int JumpBack )
{
printf( &ldquo;FIX_%s%d:\n&rdquo;, Str, Label );
printf( &ldquo;mov bh,[bx]\n&rdquo; );
printf( &ldquo;mov [bp+%s],bx\n&rdquo;, Offset );
if( *Offset != &lsquo;0&rsquo; ) printf( &ldquo;lea ax,[bp+%s]\n&rdquo;, Offset );
else printf( &ldquo;mov ax,bp\n&rdquo; );
printf( &ldquo;stosw\n&rdquo; );
if( JumpBack ) printf( &ldquo;jmp short %s%d\n&rdquo;, Str, Label );
}
void SecondPass( void )
{
printf( &ldquo;org 0%02x00h\n&rdquo;,
(Edge &lt;&lt; 7) + (New &lt;&lt; 4) + (Old &lt;&lt; 1) + 1 );
if( Edge )
{
// finished with second pass
if( New == 7 &amp;&amp; Old == 0 )
{
printf( &ldquo;cmp bp,offset DGROUP:ChangeCell\n&rdquo; );
printf( &ldquo;jne short NotEnd\n&rdquo; );
printf( &ldquo;mov word ptr es:[di],offset DGROUP:ChangeCell\n&rdquo; );
printf( &ldquo;pop di si bp ds\n&rdquo; );
printf( &ldquo;mov ChangeCell,0\n&rdquo; );
printf( &ldquo;retf\n&rdquo; );
printf( &ldquo;NotEnd:\n&rdquo; );
}
GetUpAndDown(); // ah = row, al = col, cx = up, dx = down
printf( &ldquo;push si\n&rdquo; );
printf( &ldquo;mov si,%d\n&rdquo;, WRAPLEFT ); // si = left
printf( &ldquo;cmp al,0\n&rdquo; );
printf( &ldquo;je short L%d\n&rdquo;, Label );
printf( &ldquo;mov si,%d\n&rdquo;, LEFT );
printf( &ldquo;L%d:\n&rdquo;, Label );
Test( &ldquo;si&rdquo;, &ldquo;LEFT&rdquo; );
printf( &ldquo;add si,cx\n&rdquo; );
Test( &ldquo;si&rdquo;, &ldquo;UPPERLEFT&rdquo; );
printf( &ldquo;sub si,cx\n&rdquo; );
printf( &ldquo;add si,dx\n&rdquo; );
Test( &ldquo;si&rdquo;, &ldquo;LOWERLEFT&rdquo; );
printf( &ldquo;mov si,cx\n&rdquo; );
Test( &ldquo;si&rdquo;, &ldquo;UP&rdquo; );
printf( &ldquo;mov si,dx\n&rdquo; );
Test( &ldquo;si&rdquo;, &ldquo;DOWN&rdquo; );
printf( &ldquo;cmp byte ptr [bp+_RowColMap-_CellMap],%d\n&rdquo;,
(WIDTH - 1) * 3 );
printf( &ldquo;mov si,%d\n&rdquo;, WRAPRIGHT ); // si = right
printf( &ldquo;je short R%d\n&rdquo;, Label );
printf( &ldquo;mov si,%d\n&rdquo;, RIGHT );
printf( &ldquo;R%d:\n&rdquo;, Label );
Test( &ldquo;si&rdquo;, &ldquo;RIGHT&rdquo; );
printf( &ldquo;add si,cx\n&rdquo; );
Test( &ldquo;si&rdquo;, &ldquo;UPPERRIGHT&rdquo; );
printf( &ldquo;sub si,cx\n&rdquo; );
printf( &ldquo;add si,dx\n&rdquo; );
Test( &ldquo;si&rdquo;, &ldquo;LOWERRIGHT&rdquo; );
}
else
{
Test( itoa( LEFT, Buf, 10 ), &ldquo;LEFT&rdquo; );
Test( itoa( UPPERLEFT, Buf, 10 ), &ldquo;UPPERLEFT&rdquo; );
Test( itoa( LOWERLEFT, Buf, 10 ), &ldquo;LOWERLEFT&rdquo; );
Test( itoa( UP, Buf, 10 ), &ldquo;UP&rdquo; );
Test( itoa( DOWN, Buf, 10 ), &ldquo;DOWN&rdquo; );
Test( itoa( RIGHT, Buf, 10 ), &ldquo;RIGHT&rdquo; );
Test( itoa( UPPERRIGHT, Buf, 10 ), &ldquo;UPPERRIGHT&rdquo; );
Test( itoa( LOWERRIGHT, Buf, 10 ), &ldquo;LOWERRIGHT&rdquo; );
}
if( New == Old ) Test( &ldquo;0&rdquo;, &ldquo;CENTER&rdquo; );
if( Edge ) printf( &ldquo;pop si\n&rdquo; &ldquo;mov dl,0\n&rdquo; );
Next2();
if( Edge )
{
Fix( &ldquo;si&rdquo;, &ldquo;LEFT&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;UPPERLEFT&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;LOWERLEFT&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;UP&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;DOWN&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;RIGHT&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;UPPERRIGHT&rdquo;, 1 );
Fix( &ldquo;si&rdquo;, &ldquo;LOWERRIGHT&rdquo;, New == Old );
}
else
{
Fix( itoa( LEFT, Buf, 10 ), &ldquo;LEFT&rdquo;, 1 );
Fix( itoa( UPPERLEFT, Buf, 10 ), &ldquo;UPPERLEFT&rdquo;, 1 );
Fix( itoa( LOWERLEFT, Buf, 10 ), &ldquo;LOWERLEFT&rdquo;, 1 );
Fix( itoa( UP, Buf, 10 ), &ldquo;UP&rdquo;, 1 );
Fix( itoa( DOWN, Buf, 10 ), &ldquo;DOWN&rdquo;, 1 );
Fix( itoa( RIGHT, Buf, 10 ), &ldquo;RIGHT&rdquo;, 1 );
Fix( itoa( UPPERRIGHT, Buf, 10 ), &ldquo;UPPERRIGHT&rdquo;, 1 );
Fix( itoa( LOWERRIGHT, Buf, 10 ), &ldquo;LOWERRIGHT&rdquo;, New == Old );
}
if( New == Old ) Fix( &ldquo;0&rdquo;, &ldquo;CENTER&rdquo;, 0 );
if( Edge ) printf( &ldquo;pop si\n&rdquo; &ldquo;mov dl,0\n&rdquo; );
Next2();
}
void main( void )
{
char *Seg = &ldquo;ds&rdquo;;
BuildMaps();
printf( &ldquo;DGROUP group _DATA\n&rdquo; );
printf( &ldquo;LIFE segment &lsquo;CODE&rsquo;\n&rdquo; );
printf( &ldquo;assume cs:LIFE,ds:DGROUP,ss:DGROUP,es:NOTHING\n&rdquo; );
printf( &ldquo;.386C\n&rdquo; &ldquo;public _NextGen\n\n&rdquo; );
for( Edge = 0; Edge &lt;= 1; Edge++ )
{
for( New = 0; New &lt; 8; New++ )
{
for( Old = 0; Old &lt; 8; Old++ )
{
if( New != Old ) FirstPass(); Label++;
SecondPass(); Label++;
}
}
}
// finished with first pass
printf( &ldquo;org 0\n&rdquo; );
printf( &ldquo;mov si,Change1\n&rdquo; );
printf( &ldquo;mov di,Change2\n&rdquo; );
printf( &ldquo;mov Change1,di\n&rdquo; );
printf( &ldquo;mov Change2,si\n&rdquo; );
printf( &ldquo;mov ChangeCell,0F000h\n&rdquo; );
printf( &ldquo;mov ax,seg _LDMAP\n&rdquo; );
printf( &ldquo;mov ds,ax\n&rdquo; );
Next2();
// entry point
printf( &ldquo;_NextGen: push ds bp si di\n&rdquo; &ldquo;cld\n&rdquo; );
if( WIDTH * HEIGHT &gt; LIST_LIMIT ) Seg = &ldquo;seg _CHANGE&rdquo;;
printf( &ldquo;mov ax,%s\n&rdquo;, Seg );
printf( &ldquo;mov es,ax\n&rdquo; );
#ifndef NODRAW
printf( &ldquo;mov ax,0A000h\n&rdquo; );
printf( &ldquo;mov fs,ax\n&rdquo; );
#endif
printf( &ldquo;mov si,Change1\n&rdquo; );
printf( &ldquo;mov dl,0\n&rdquo; );
Next1();
printf( &ldquo;LIFE ends\nend\n&rdquo; );
}
</pre>
<center>
<table border="1">
<tr>
<td>
<a href="18-02.html">Previous</a>
</td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td>
<a href="18-04.html">Next</a>
</td>
</tr>
</table>
</center>
<hr width="90%" size="1" noshade="noshade" />
<div align="center">
Graphics Programming Black Book &copy; 2001 Michael Abrash
</div>
</body>
</html>