abrash-black-book/18-03.html
2013-12-30 12:21:49 +11:00

571 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: It's a Wonderful Life</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=18//-->
<!--PAGES=352-361//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
<CENTER>
<TABLE BORDER>
<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><BR></P>
<P><B>LISTING 18.1 BUILD.BAT</B></P>
<!-- CODE SNIP //-->
<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>
<!-- END CODE SNIP //-->
<P><B>LISTING 18.2 LCOMP.C</B></P>
<!-- CODE //-->
<PRE>
// LCOMP.C
//
// Life compiler, ver 1.3
//
// David Stafford
//
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &#147;life.h&#148;
#define LIST_LIMIT (46 * 138) // when we need to use es:
int Old, New, Edge, Label;
char Buf[ 20 ];
void Next1( void )
{
char *Seg = &#147;&#148;;
if( WIDTH * HEIGHT &gt; LIST_LIMIT ) Seg = &#147;es:&#148;;
printf( &#147;mov bp,%s[si]\n&#148;, Seg );
printf( &#147;add si,2\n&#148; );
printf( &#147;mov dh,[bp&#43;1]\n&#148; );
printf( &#147;and dh,0FEh\n&#148; );
printf( &#147;jmp dx\n&#148; );
}
void Next2( void )
{
printf( &#147;mov bp,es:[si]\n&#148; );
printf( &#147;add si,2\n&#148; );
printf( &#147;mov dh,[bp&#43;1]\n&#148; );
printf( &#147;or dh,1\n&#148; );
printf( &#147;jmp dx\n&#148; );
}
void BuildMaps( void )
{
unsigned short i, j, Size, x = 0, y, N1, N2, N3, C1, C2, C3;
printf( &#147;_DATA segment &#145;DATA&#146;\nalign 2\n&#148; );
printf( &#147;public _CellMap\n&#148; );
printf( &#147;_CellMap label word\n&#148; );
for( j = 0; j &lt; HEIGHT; j&#43;&#43; )
{
for( i = 0; i &lt; WIDTH; i&#43;&#43; )
{
if( i == 0 || i == WIDTH-1 || j == 0 || j == HEIGHT-1 )
{
printf( &#147;dw 8000h\n&#148; );
}
else
{
printf( &#147;dw 0\n&#148; );
}
}
}
printf( &#147;ChangeCell dw 0\n&#148; );
printf( &#147;_RowColMap label word\n&#148; );
for( j = 0; j &lt; HEIGHT; j&#43;&#43; )
{
for( i = 0; i &lt; WIDTH; i&#43;&#43; )
{
printf( &#147;dw 0%02x%02xh\n&#148;, j, i * 3 );
}
}
if( WIDTH * HEIGHT &gt; LIST_LIMIT )
{
printf( &#147;Change1 dw offset _CHANGE:_ChangeList1\n&#148; );
printf( &#147;Change2 dw offset _CHANGE:_ChangeList2\n&#148; );
printf( &#147;ends\n\n&#148; );
printf( &#147;_CHANGE segment para public &#145;FAR_DATA&#146;\n&#148; );
}
else
{
printf( &#147;Change1 dw offset DGROUP:_ChangeList1\n&#148; );
printf( &#147;Change2 dw offset DGROUP:_ChangeList2\n&#148; );
}
Size = WIDTH * HEIGHT &#43; 1;
printf( &#147;public _ChangeList1\n_ChangeList1 label word\n&#148; );
printf( &#147;dw %d dup (offset DGROUP:ChangeCell)\n&#148;, Size );
printf( &#147;public _ChangeList2\n_ChangeList2 label word\n&#148; );
printf( &#147;dw %d dup (offset DGROUP:ChangeCell)\n&#148;, Size );
printf( &#147;ends\n\n&#148; );
printf( &#147;_LDMAP segment para public &#145;FAR_DATA&#146;\n&#148; );
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 &#43; C2 == 2) || (N1 &#43; C2 == 3)) )
{
y |= 0x4000;
}
if( !C1 &amp&amp (N1 &#43; C2 == 3) )
{
y |= 0x4000;
}
if( C2 &amp&amp ((N2 &#43; C1 &#43; C3 == 2) || (N2 &#43; C1 &#43; C3 == 3)) )
{
y |= 0x2000;
}
if( !C2 &amp&amp (N2 &#43; C1 &#43; C3 == 3) )
{
y |= 0x2000;
}
if( C3 &amp&amp ((N3 &#43; C2 == 2) || (N3 &#43; C2 == 3)) )
{
y |= 0x1000;
}
if( !C3 &amp&amp (N3 &#43; C2 == 3) )
{
y |= 0x1000;
}
printf( &#147;db 0%02xh\n&#148;, y &gt;&gt; 8 );
}
while( &#43;&#43;x != 0 );
printf( &#147;ends\n\n&#148; );
}
void GetUpAndDown( void )
{
printf( &#147;mov ax,[bp&#43;_RowColMap-_CellMap]\n&#148; );
printf( &#147;or ah,ah\n&#148; );
printf( &#147;mov dx,%d\n&#148;, DOWN );
printf( &#147;mov cx,%d\n&#148;, WRAPUP );
printf( &#147;jz short D%d\n&#148;, Label );
printf( &#147;cmp ah,%d\n&#148;, HEIGHT - 1 );
printf( &#147;mov cx,%d\n&#148;, UP );
printf( &#147;jb short D%d\n&#148;, Label );
printf( &#147;mov dx,%d\n&#148;, WRAPDOWN );
printf( &#147;D%d:\n&#148;, Label );
}
void FirstPass( void )
{
char *Op;
unsigned short UpDown = 0;
printf( &#147;org 0%02x00h\n&#148;, (Edge &lt;&lt; 7) &#43; (New &lt;&lt; 4) &#43; (Old &lt;&lt; 1) );
// reset cell
printf( &#147;xor byte ptr [bp&#43;1],0%02xh\n&#148;, (New ^ Old) &lt;&lt; 1 );
// get the screen address and update the display
#ifndef NODRAW
printf( &#147;mov al,160\n&#148; );
printf( &#147;mov bx,[bp&#43;_RowColMap-_CellMap]\n&#148; );
printf( &#147;mul bh\n&#148; );
printf( &#147;add ax,ax\n&#148; );
printf( &#147;mov bh,0\n&#148; );
printf( &#147;add bx,ax\n&#148; ); // bx = screen offset
if( ((New ^ Old) &amp 6) == 6 )
{
printf( &#147;mov word ptr fs:[bx],0%02x%02xh\n&#148;,
(New &amp 2) ? 15 : 0,
(New &amp 4) ? 15 : 0 );
if( (New ^ Old) &amp 1 )
{
printf( &#147;mov byte ptr fs:[bx&#43;2],%s\n&#148;,
(New &amp 1) ? &#147;15&#148; : &#147;dl&#148; );
}
}
else
{
if( ((New ^ Old) &amp 3) == 3 )
{
printf( &#147;mov word ptr fs:[bx&#43;1],0%02x%02xh\n&#148;,
(New &amp 1) ? 15 : 0,
(New &amp 2) ? 15 : 0 );
}
else
{
if( (New ^ Old) &amp 2 )
{
printf( &#147;mov byte ptr fs:[bx&#43;1],%s\n&#148;,
(New &amp 2) ? &#147;15&#148; : &#147;dl&#148; );
}
if( (New ^ Old) &amp 1 )
{
printf( &#147;mov byte ptr fs:[bx&#43;2],%s\n&#148;,
(New &amp 1) ? &#147;15&#148; : &#147;dl&#148; );
}
}
if( (New ^ Old) &amp 4 )
{
printf( &#147;mov byte ptr fs:[bx],%s\n&#148;,
(New &amp 4) ? &#147;15&#148; : &#147;dl&#148; );
}
}
#endif
if( (New ^ Old) &amp 4 ) UpDown &#43;= (New &amp 4) ? 0x48 : -0x48;
if( (New ^ Old) &amp 2 ) UpDown &#43;= (New &amp 2) ? 0x49 : -0x49;
if( (New ^ Old) &amp 1 ) UpDown &#43;= (New &amp 1) ? 0x09 : -0x09;
if( Edge )
{
GetUpAndDown(); // ah = row, al = col, cx = up, dx = down
if( (New ^ Old) &amp 4 )
{
printf( &#147;mov di,%d\n&#148;, WRAPLEFT ); // di = left
printf( &#147;cmp al,0\n&#148; );
printf( &#147;je short L%d\n&#148;, Label );
printf( &#147;mov di,%d\n&#148;, LEFT );
printf( &#147;L%d:\n&#148;, Label );
if( New &amp 4 ) Op = &#147;inc&#148;;
else Op = &#147;dec&#148;;
printf( &#147;%s word ptr [bp&#43;di]\n&#148;, Op );
printf( &#147;add di,cx\n&#148; );
printf( &#147;%s word ptr [bp&#43;di]\n&#148;, Op );
printf( &#147;sub di,cx\n&#148; );
printf( &#147;add di,dx\n&#148; );
printf( &#147;%s word ptr [bp&#43;di]\n&#148;, Op );
}
if( (New ^ Old) &amp 1 )
{
printf( &#147;mov di,%d\n&#148;, WRAPRIGHT ); // di = right
printf( &#147;cmp al,%d\n&#148;, (WIDTH - 1) * 3 );
printf( &#147;je short R%d\n&#148;, Label );
printf( &#147;mov di,%d\n&#148;, RIGHT );
printf( &#147;R%d:\n&#148;, Label );
if( New &amp 1 ) Op = &#147;add&#148;;
else Op = &#147;sub&#148;;
printf( &#147;%s word ptr [bp&#43;di],40h\n&#148;, Op );
printf( &#147;add di,cx\n&#148; );
printf( &#147;%s word ptr [bp&#43;di],40h\n&#148;, Op );
printf( &#147;sub di,cx\n&#148; );
printf( &#147;add di,dx\n&#148; );
printf( &#147;%s word ptr [bp&#43;di],40h\n&#148;, Op );
}
printf( &#147;mov di,cx\n&#148; );
printf( &#147;add word ptr [bp&#43;di],%d\n&#148;, UpDown );
printf( &#147;mov di,dx\n&#148; );
printf( &#147;add word ptr [bp&#43;di],%d\n&#148;, UpDown );
printf( &#147;mov dl,0\n&#148; );
}
else
{
if( (New ^ Old) &amp 4 )
{
if( New &amp 4 ) Op = &#147;inc&#148;;
else Op = &#147;dec&#148;;
printf( &#147;%s byte ptr [bp&#43;%d]\n&#148;, Op, LEFT );
printf( &#147;%s byte ptr [bp&#43;%d]\n&#148;, Op, UPPERLEFT );
printf( &#147;%s byte ptr [bp&#43;%d]\n&#148;, Op, LOWERLEFT );
}
if( (New ^ Old) &amp 1 )
{
if( New &amp 1 ) Op = &#147;add&#148;;
else Op = &#147;sub&#148;;
printf( &#147;%s word ptr [bp&#43;%d],40h\n&#148;, Op, RIGHT );
printf( &#147;%s word ptr [bp&#43;%d],40h\n&#148;, Op, UPPERRIGHT );
printf( &#147;%s word ptr [bp&#43;%d],40h\n&#148;, Op, LOWERRIGHT );
}
if( abs( UpDown ) &gt; 1 )
{
printf( &#147;add word ptr [bp&#43;%d],%d\n&#148;, UP, UpDown );
printf( &#147;add word ptr [bp&#43;%d],%d\n&#148;, DOWN, UpDown );
}
else
{
if( UpDown == 1 ) Op = &#147;inc&#148;;
else Op = &#147;dec&#148;;
printf( &#147;%s byte ptr [bp&#43;%d]\n&#148;, Op, UP );
printf( &#147;%s byte ptr [bp&#43;%d]\n&#148;, Op, DOWN );
}
}
Next1();
}
void Test( char *Offset, char *Str )
{
printf( &#147;mov bx,[bp&#43;%s]\n&#148;, Offset );
printf( &#147;cmp bh,[bx]\n&#148; );
printf( &#147;jnz short FIX_%s%d\n&#148;, Str, Label );
printf( &#147;%s%d:\n&#148;, Str, Label );
}
void Fix( char *Offset, char *Str, int JumpBack )
{
printf( &#147;FIX_%s%d:\n&#148;, Str, Label );
printf( &#147;mov bh,[bx]\n&#148; );
printf( &#147;mov [bp&#43;%s],bx\n&#148;, Offset );
if( *Offset != &#145;0&#146; ) printf( &#147;lea ax,[bp&#43;%s]\n&#148;, Offset );
else printf( &#147;mov ax,bp\n&#148; );
printf( &#147;stosw\n&#148; );
if( JumpBack ) printf( &#147;jmp short %s%d\n&#148;, Str, Label );
}
void SecondPass( void )
{
printf( &#147;org 0%02x00h\n&#148;,
(Edge &lt;&lt; 7) &#43; (New &lt;&lt; 4) &#43; (Old &lt;&lt; 1) &#43; 1 );
if( Edge )
{
// finished with second pass
if( New == 7 &amp&amp Old == 0 )
{
printf( &#147;cmp bp,offset DGROUP:ChangeCell\n&#148; );
printf( &#147;jne short NotEnd\n&#148; );
printf( &#147;mov word ptr es:[di],offset DGROUP:ChangeCell\n&#148; );
printf( &#147;pop di si bp ds\n&#148; );
printf( &#147;mov ChangeCell,0\n&#148; );
printf( &#147;retf\n&#148; );
printf( &#147;NotEnd:\n&#148; );
}
GetUpAndDown(); // ah = row, al = col, cx = up, dx = down
printf( &#147;push si\n&#148; );
printf( &#147;mov si,%d\n&#148;, WRAPLEFT ); // si = left
printf( &#147;cmp al,0\n&#148; );
printf( &#147;je short L%d\n&#148;, Label );
printf( &#147;mov si,%d\n&#148;, LEFT );
printf( &#147;L%d:\n&#148;, Label );
Test( &#147;si&#148;, &#147;LEFT&#148; );
printf( &#147;add si,cx\n&#148; );
Test( &#147;si&#148;, &#147;UPPERLEFT&#148; );
printf( &#147;sub si,cx\n&#148; );
printf( &#147;add si,dx\n&#148; );
Test( &#147;si&#148;, &#147;LOWERLEFT&#148; );
printf( &#147;mov si,cx\n&#148; );
Test( &#147;si&#148;, &#147;UP&#148; );
printf( &#147;mov si,dx\n&#148; );
Test( &#147;si&#148;, &#147;DOWN&#148; );
printf( &#147;cmp byte ptr [bp&#43;_RowColMap-_CellMap],%d\n&#148;,
(WIDTH - 1) * 3 );
printf( &#147;mov si,%d\n&#148;, WRAPRIGHT ); // si = right
printf( &#147;je short R%d\n&#148;, Label );
printf( &#147;mov si,%d\n&#148;, RIGHT );
printf( &#147;R%d:\n&#148;, Label );
Test( &#147;si&#148;, &#147;RIGHT&#148; );
printf( &#147;add si,cx\n&#148; );
Test( &#147;si&#148;, &#147;UPPERRIGHT&#148; );
printf( &#147;sub si,cx\n&#148; );
printf( &#147;add si,dx\n&#148; );
Test( &#147;si&#148;, &#147;LOWERRIGHT&#148; );
}
else
{
Test( itoa( LEFT, Buf, 10 ), &#147;LEFT&#148; );
Test( itoa( UPPERLEFT, Buf, 10 ), &#147;UPPERLEFT&#148; );
Test( itoa( LOWERLEFT, Buf, 10 ), &#147;LOWERLEFT&#148; );
Test( itoa( UP, Buf, 10 ), &#147;UP&#148; );
Test( itoa( DOWN, Buf, 10 ), &#147;DOWN&#148; );
Test( itoa( RIGHT, Buf, 10 ), &#147;RIGHT&#148; );
Test( itoa( UPPERRIGHT, Buf, 10 ), &#147;UPPERRIGHT&#148; );
Test( itoa( LOWERRIGHT, Buf, 10 ), &#147;LOWERRIGHT&#148; );
}
if( New == Old ) Test( &#147;0&#148;, &#147;CENTER&#148; );
if( Edge ) printf( &#147;pop si\n&#148; &#147;mov dl,0\n&#148; );
Next2();
if( Edge )
{
Fix( &#147;si&#148;, &#147;LEFT&#148;, 1 );
Fix( &#147;si&#148;, &#147;UPPERLEFT&#148;, 1 );
Fix( &#147;si&#148;, &#147;LOWERLEFT&#148;, 1 );
Fix( &#147;si&#148;, &#147;UP&#148;, 1 );
Fix( &#147;si&#148;, &#147;DOWN&#148;, 1 );
Fix( &#147;si&#148;, &#147;RIGHT&#148;, 1 );
Fix( &#147;si&#148;, &#147;UPPERRIGHT&#148;, 1 );
Fix( &#147;si&#148;, &#147;LOWERRIGHT&#148;, New == Old );
}
else
{
Fix( itoa( LEFT, Buf, 10 ), &#147;LEFT&#148;, 1 );
Fix( itoa( UPPERLEFT, Buf, 10 ), &#147;UPPERLEFT&#148;, 1 );
Fix( itoa( LOWERLEFT, Buf, 10 ), &#147;LOWERLEFT&#148;, 1 );
Fix( itoa( UP, Buf, 10 ), &#147;UP&#148;, 1 );
Fix( itoa( DOWN, Buf, 10 ), &#147;DOWN&#148;, 1 );
Fix( itoa( RIGHT, Buf, 10 ), &#147;RIGHT&#148;, 1 );
Fix( itoa( UPPERRIGHT, Buf, 10 ), &#147;UPPERRIGHT&#148;, 1 );
Fix( itoa( LOWERRIGHT, Buf, 10 ), &#147;LOWERRIGHT&#148;, New == Old );
}
if( New == Old ) Fix( &#147;0&#148;, &#147;CENTER&#148;, 0 );
if( Edge ) printf( &#147;pop si\n&#148; &#147;mov dl,0\n&#148; );
Next2();
}
void main( void )
{
char *Seg = &#147;ds&#148;;
BuildMaps();
printf( &#147;DGROUP group _DATA\n&#148; );
printf( &#147;LIFE segment &#145;CODE&#146;\n&#148; );
printf( &#147;assume cs:LIFE,ds:DGROUP,ss:DGROUP,es:NOTHING\n&#148; );
printf( &#147;.386C\n&#148; &#147;public _NextGen\n\n&#148; );
for( Edge = 0; Edge &lt;= 1; Edge&#43;&#43; )
{
for( New = 0; New &lt; 8; New&#43;&#43; )
{
for( Old = 0; Old &lt; 8; Old&#43;&#43; )
{
if( New != Old ) FirstPass(); Label&#43;&#43;;
SecondPass(); Label&#43;&#43;;
}
}
}
// finished with first pass
printf( &#147;org 0\n&#148; );
printf( &#147;mov si,Change1\n&#148; );
printf( &#147;mov di,Change2\n&#148; );
printf( &#147;mov Change1,di\n&#148; );
printf( &#147;mov Change2,si\n&#148; );
printf( &#147;mov ChangeCell,0F000h\n&#148; );
printf( &#147;mov ax,seg _LDMAP\n&#148; );
printf( &#147;mov ds,ax\n&#148; );
Next2();
// entry point
printf( &#147;_NextGen: push ds bp si di\n&#148; &#147;cld\n&#148; );
if( WIDTH * HEIGHT &gt; LIST_LIMIT ) Seg = &#147;seg _CHANGE&#148;;
printf( &#147;mov ax,%s\n&#148;, Seg );
printf( &#147;mov es,ax\n&#148; );
#ifndef NODRAW
printf( &#147;mov ax,0A000h\n&#148; );
printf( &#147;mov fs,ax\n&#148; );
#endif
printf( &#147;mov si,Change1\n&#148; );
printf( &#147;mov dl,0\n&#148; );
Next1();
printf( &#147;LIFE ends\nend\n&#148; );
}
</PRE>
<!-- END CODE //-->
<P><BR></P>
<CENTER>
<TABLE BORDER>
<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>
<div align="center">
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book &copy; 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 -->