571 lines
17 KiB
HTML
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 > 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include “life.h”
|
|
|
|
#define LIST_LIMIT (46 * 138) // when we need to use es:
|
|
|
|
int Old, New, Edge, Label;
|
|
char Buf[ 20 ];
|
|
|
|
void Next1( void )
|
|
{
|
|
char *Seg = “”;
|
|
|
|
if( WIDTH * HEIGHT > LIST_LIMIT ) Seg = “es:”;
|
|
|
|
printf( “mov bp,%s[si]\n”, Seg );
|
|
printf( “add si,2\n” );
|
|
printf( “mov dh,[bp+1]\n” );
|
|
printf( “and dh,0FEh\n” );
|
|
printf( “jmp dx\n” );
|
|
}
|
|
|
|
void Next2( void )
|
|
{
|
|
printf( “mov bp,es:[si]\n” );
|
|
printf( “add si,2\n” );
|
|
printf( “mov dh,[bp+1]\n” );
|
|
printf( “or dh,1\n” );
|
|
printf( “jmp dx\n” );
|
|
}
|
|
|
|
void BuildMaps( void )
|
|
{
|
|
unsigned short i, j, Size, x = 0, y, N1, N2, N3, C1, C2, C3;
|
|
|
|
printf( “_DATA segment ‘DATA’\nalign 2\n” );
|
|
printf( “public _CellMap\n” );
|
|
printf( “_CellMap label word\n” );
|
|
|
|
for( j = 0; j < HEIGHT; j++ )
|
|
{
|
|
for( i = 0; i < WIDTH; i++ )
|
|
{
|
|
if( i == 0 || i == WIDTH-1 || j == 0 || j == HEIGHT-1 )
|
|
{
|
|
printf( “dw 8000h\n” );
|
|
}
|
|
else
|
|
{
|
|
printf( “dw 0\n” );
|
|
}
|
|
}
|
|
}
|
|
|
|
printf( “ChangeCell dw 0\n” );
|
|
printf( “_RowColMap label word\n” );
|
|
|
|
for( j = 0; j < HEIGHT; j++ )
|
|
{
|
|
for( i = 0; i < WIDTH; i++ )
|
|
{
|
|
printf( “dw 0%02x%02xh\n”, j, i * 3 );
|
|
}
|
|
}
|
|
|
|
if( WIDTH * HEIGHT > LIST_LIMIT )
|
|
{
|
|
printf( “Change1 dw offset _CHANGE:_ChangeList1\n” );
|
|
printf( “Change2 dw offset _CHANGE:_ChangeList2\n” );
|
|
printf( “ends\n\n” );
|
|
printf( “_CHANGE segment para public ‘FAR_DATA’\n” );
|
|
}
|
|
else
|
|
{
|
|
printf( “Change1 dw offset DGROUP:_ChangeList1\n” );
|
|
printf( “Change2 dw offset DGROUP:_ChangeList2\n” );
|
|
}
|
|
|
|
Size = WIDTH * HEIGHT + 1;
|
|
|
|
printf( “public _ChangeList1\n_ChangeList1 label word\n” );
|
|
printf( “dw %d dup (offset DGROUP:ChangeCell)\n”, Size );
|
|
printf( “public _ChangeList2\n_ChangeList2 label word\n” );
|
|
printf( “dw %d dup (offset DGROUP:ChangeCell)\n”, Size );
|
|
printf( “ends\n\n” );
|
|
|
|
printf( “_LDMAP segment para public ‘FAR_DATA’\n” );
|
|
|
|
do
|
|
{
|
|
// Current cell states
|
|
C1 = (x & 0x0800) >> 11;
|
|
C2 = (x & 0x0400) >> 10;
|
|
C3 = (x & 0x0200) >> 9;
|
|
|
|
// Neighbor counts
|
|
N1 = (x & 0x01C0) >> 6;
|
|
N2 = (x & 0x0038) >> 3;
|
|
N3 = (x & 0x0007);
|
|
|
|
y = x & 0x8FFF; // Preserve all but the next generation states
|
|
|
|
if( C1 && ((N1 + C2 == 2) || (N1 + C2 == 3)) )
|
|
{
|
|
y |= 0x4000;
|
|
}
|
|
|
|
if( !C1 && (N1 + C2 == 3) )
|
|
{
|
|
y |= 0x4000;
|
|
}
|
|
|
|
if( C2 && ((N2 + C1 + C3 == 2) || (N2 + C1 + C3 == 3)) )
|
|
{
|
|
y |= 0x2000;
|
|
}
|
|
|
|
if( !C2 && (N2 + C1 + C3 == 3) )
|
|
{
|
|
y |= 0x2000;
|
|
}
|
|
|
|
if( C3 && ((N3 + C2 == 2) || (N3 + C2 == 3)) )
|
|
{
|
|
y |= 0x1000;
|
|
}
|
|
|
|
if( !C3 && (N3 + C2 == 3) )
|
|
{
|
|
y |= 0x1000;
|
|
}
|
|
|
|
printf( “db 0%02xh\n”, y >> 8 );
|
|
}
|
|
while( ++x != 0 );
|
|
|
|
printf( “ends\n\n” );
|
|
}
|
|
|
|
void GetUpAndDown( void )
|
|
{
|
|
printf( “mov ax,[bp+_RowColMap-_CellMap]\n” );
|
|
printf( “or ah,ah\n” );
|
|
printf( “mov dx,%d\n”, DOWN );
|
|
printf( “mov cx,%d\n”, WRAPUP );
|
|
printf( “jz short D%d\n”, Label );
|
|
printf( “cmp ah,%d\n”, HEIGHT - 1 );
|
|
printf( “mov cx,%d\n”, UP );
|
|
printf( “jb short D%d\n”, Label );
|
|
printf( “mov dx,%d\n”, WRAPDOWN );
|
|
printf( “D%d:\n”, Label );
|
|
}
|
|
|
|
void FirstPass( void )
|
|
{
|
|
char *Op;
|
|
unsigned short UpDown = 0;
|
|
|
|
printf( “org 0%02x00h\n”, (Edge << 7) + (New << 4) + (Old << 1) );
|
|
|
|
// reset cell
|
|
printf( “xor byte ptr [bp+1],0%02xh\n”, (New ^ Old) << 1 );
|
|
|
|
// get the screen address and update the display
|
|
#ifndef NODRAW
|
|
printf( “mov al,160\n” );
|
|
printf( “mov bx,[bp+_RowColMap-_CellMap]\n” );
|
|
printf( “mul bh\n” );
|
|
printf( “add ax,ax\n” );
|
|
printf( “mov bh,0\n” );
|
|
printf( “add bx,ax\n” ); // bx = screen offset
|
|
|
|
if( ((New ^ Old) & 6) == 6 )
|
|
{
|
|
printf( “mov word ptr fs:[bx],0%02x%02xh\n”,
|
|
(New & 2) ? 15 : 0,
|
|
(New & 4) ? 15 : 0 );
|
|
|
|
if( (New ^ Old) & 1 )
|
|
{
|
|
printf( “mov byte ptr fs:[bx+2],%s\n”,
|
|
(New & 1) ? “15” : “dl” );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( ((New ^ Old) & 3) == 3 )
|
|
{
|
|
printf( “mov word ptr fs:[bx+1],0%02x%02xh\n”,
|
|
(New & 1) ? 15 : 0,
|
|
(New & 2) ? 15 : 0 );
|
|
}
|
|
else
|
|
{
|
|
if( (New ^ Old) & 2 )
|
|
{
|
|
printf( “mov byte ptr fs:[bx+1],%s\n”,
|
|
(New & 2) ? “15” : “dl” );
|
|
}
|
|
|
|
if( (New ^ Old) & 1 )
|
|
{
|
|
printf( “mov byte ptr fs:[bx+2],%s\n”,
|
|
(New & 1) ? “15” : “dl” );
|
|
}
|
|
}
|
|
|
|
if( (New ^ Old) & 4 )
|
|
{
|
|
printf( “mov byte ptr fs:[bx],%s\n”,
|
|
(New & 4) ? “15” : “dl” );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if( (New ^ Old) & 4 ) UpDown += (New & 4) ? 0x48 : -0x48;
|
|
if( (New ^ Old) & 2 ) UpDown += (New & 2) ? 0x49 : -0x49;
|
|
if( (New ^ Old) & 1 ) UpDown += (New & 1) ? 0x09 : -0x09;
|
|
|
|
if( Edge )
|
|
{
|
|
GetUpAndDown(); // ah = row, al = col, cx = up, dx = down
|
|
|
|
if( (New ^ Old) & 4 )
|
|
{
|
|
printf( “mov di,%d\n”, WRAPLEFT ); // di = left
|
|
printf( “cmp al,0\n” );
|
|
printf( “je short L%d\n”, Label );
|
|
printf( “mov di,%d\n”, LEFT );
|
|
printf( “L%d:\n”, Label );
|
|
|
|
if( New & 4 ) Op = “inc”;
|
|
else Op = “dec”;
|
|
|
|
printf( “%s word ptr [bp+di]\n”, Op );
|
|
printf( “add di,cx\n” );
|
|
printf( “%s word ptr [bp+di]\n”, Op );
|
|
printf( “sub di,cx\n” );
|
|
printf( “add di,dx\n” );
|
|
printf( “%s word ptr [bp+di]\n”, Op );
|
|
}
|
|
|
|
if( (New ^ Old) & 1 )
|
|
{
|
|
printf( “mov di,%d\n”, WRAPRIGHT ); // di = right
|
|
printf( “cmp al,%d\n”, (WIDTH - 1) * 3 );
|
|
printf( “je short R%d\n”, Label );
|
|
printf( “mov di,%d\n”, RIGHT );
|
|
printf( “R%d:\n”, Label );
|
|
|
|
if( New & 1 ) Op = “add”;
|
|
else Op = “sub”;
|
|
|
|
printf( “%s word ptr [bp+di],40h\n”, Op );
|
|
printf( “add di,cx\n” );
|
|
printf( “%s word ptr [bp+di],40h\n”, Op );
|
|
printf( “sub di,cx\n” );
|
|
printf( “add di,dx\n” );
|
|
printf( “%s word ptr [bp+di],40h\n”, Op );
|
|
}
|
|
|
|
printf( “mov di,cx\n” );
|
|
printf( “add word ptr [bp+di],%d\n”, UpDown );
|
|
printf( “mov di,dx\n” );
|
|
printf( “add word ptr [bp+di],%d\n”, UpDown );
|
|
|
|
printf( “mov dl,0\n” );
|
|
}
|
|
else
|
|
{
|
|
if( (New ^ Old) & 4 )
|
|
{
|
|
if( New & 4 ) Op = “inc”;
|
|
else Op = “dec”;
|
|
|
|
printf( “%s byte ptr [bp+%d]\n”, Op, LEFT );
|
|
printf( “%s byte ptr [bp+%d]\n”, Op, UPPERLEFT );
|
|
printf( “%s byte ptr [bp+%d]\n”, Op, LOWERLEFT );
|
|
}
|
|
|
|
if( (New ^ Old) & 1 )
|
|
{
|
|
if( New & 1 ) Op = “add”;
|
|
else Op = “sub”;
|
|
|
|
printf( “%s word ptr [bp+%d],40h\n”, Op, RIGHT );
|
|
printf( “%s word ptr [bp+%d],40h\n”, Op, UPPERRIGHT );
|
|
printf( “%s word ptr [bp+%d],40h\n”, Op, LOWERRIGHT );
|
|
}
|
|
|
|
if( abs( UpDown ) > 1 )
|
|
{
|
|
printf( “add word ptr [bp+%d],%d\n”, UP, UpDown );
|
|
printf( “add word ptr [bp+%d],%d\n”, DOWN, UpDown );
|
|
}
|
|
else
|
|
{
|
|
if( UpDown == 1 ) Op = “inc”;
|
|
else Op = “dec”;
|
|
|
|
printf( “%s byte ptr [bp+%d]\n”, Op, UP );
|
|
printf( “%s byte ptr [bp+%d]\n”, Op, DOWN );
|
|
}
|
|
}
|
|
|
|
Next1();
|
|
}
|
|
|
|
void Test( char *Offset, char *Str )
|
|
{
|
|
printf( “mov bx,[bp+%s]\n”, Offset );
|
|
printf( “cmp bh,[bx]\n” );
|
|
printf( “jnz short FIX_%s%d\n”, Str, Label );
|
|
printf( “%s%d:\n”, Str, Label );
|
|
}
|
|
|
|
void Fix( char *Offset, char *Str, int JumpBack )
|
|
{
|
|
printf( “FIX_%s%d:\n”, Str, Label );
|
|
printf( “mov bh,[bx]\n” );
|
|
printf( “mov [bp+%s],bx\n”, Offset );
|
|
|
|
if( *Offset != ‘0’ ) printf( “lea ax,[bp+%s]\n”, Offset );
|
|
else printf( “mov ax,bp\n” );
|
|
|
|
printf( “stosw\n” );
|
|
|
|
if( JumpBack ) printf( “jmp short %s%d\n”, Str, Label );
|
|
}
|
|
|
|
void SecondPass( void )
|
|
{
|
|
printf( “org 0%02x00h\n”,
|
|
(Edge << 7) + (New << 4) + (Old << 1) + 1 );
|
|
|
|
if( Edge )
|
|
{
|
|
// finished with second pass
|
|
if( New == 7 && Old == 0 )
|
|
{
|
|
printf( “cmp bp,offset DGROUP:ChangeCell\n” );
|
|
printf( “jne short NotEnd\n” );
|
|
printf( “mov word ptr es:[di],offset DGROUP:ChangeCell\n” );
|
|
printf( “pop di si bp ds\n” );
|
|
printf( “mov ChangeCell,0\n” );
|
|
printf( “retf\n” );
|
|
printf( “NotEnd:\n” );
|
|
}
|
|
|
|
GetUpAndDown(); // ah = row, al = col, cx = up, dx = down
|
|
|
|
printf( “push si\n” );
|
|
printf( “mov si,%d\n”, WRAPLEFT ); // si = left
|
|
printf( “cmp al,0\n” );
|
|
printf( “je short L%d\n”, Label );
|
|
printf( “mov si,%d\n”, LEFT );
|
|
printf( “L%d:\n”, Label );
|
|
|
|
Test( “si”, “LEFT” );
|
|
printf( “add si,cx\n” );
|
|
Test( “si”, “UPPERLEFT” );
|
|
printf( “sub si,cx\n” );
|
|
printf( “add si,dx\n” );
|
|
Test( “si”, “LOWERLEFT” );
|
|
|
|
printf( “mov si,cx\n” );
|
|
Test( “si”, “UP” );
|
|
printf( “mov si,dx\n” );
|
|
Test( “si”, “DOWN” );
|
|
|
|
printf( “cmp byte ptr [bp+_RowColMap-_CellMap],%d\n”,
|
|
(WIDTH - 1) * 3 );
|
|
|
|
printf( “mov si,%d\n”, WRAPRIGHT ); // si = right
|
|
printf( “je short R%d\n”, Label );
|
|
printf( “mov si,%d\n”, RIGHT );
|
|
printf( “R%d:\n”, Label );
|
|
|
|
Test( “si”, “RIGHT” );
|
|
printf( “add si,cx\n” );
|
|
Test( “si”, “UPPERRIGHT” );
|
|
printf( “sub si,cx\n” );
|
|
printf( “add si,dx\n” );
|
|
Test( “si”, “LOWERRIGHT” );
|
|
}
|
|
else
|
|
{
|
|
Test( itoa( LEFT, Buf, 10 ), “LEFT” );
|
|
Test( itoa( UPPERLEFT, Buf, 10 ), “UPPERLEFT” );
|
|
Test( itoa( LOWERLEFT, Buf, 10 ), “LOWERLEFT” );
|
|
Test( itoa( UP, Buf, 10 ), “UP” );
|
|
Test( itoa( DOWN, Buf, 10 ), “DOWN” );
|
|
Test( itoa( RIGHT, Buf, 10 ), “RIGHT” );
|
|
Test( itoa( UPPERRIGHT, Buf, 10 ), “UPPERRIGHT” );
|
|
Test( itoa( LOWERRIGHT, Buf, 10 ), “LOWERRIGHT” );
|
|
}
|
|
|
|
if( New == Old ) Test( “0”, “CENTER” );
|
|
|
|
if( Edge ) printf( “pop si\n” “mov dl,0\n” );
|
|
|
|
Next2();
|
|
|
|
if( Edge )
|
|
{
|
|
Fix( “si”, “LEFT”, 1 );
|
|
Fix( “si”, “UPPERLEFT”, 1 );
|
|
Fix( “si”, “LOWERLEFT”, 1 );
|
|
Fix( “si”, “UP”, 1 );
|
|
Fix( “si”, “DOWN”, 1 );
|
|
Fix( “si”, “RIGHT”, 1 );
|
|
Fix( “si”, “UPPERRIGHT”, 1 );
|
|
Fix( “si”, “LOWERRIGHT”, New == Old );
|
|
}
|
|
else
|
|
{
|
|
Fix( itoa( LEFT, Buf, 10 ), “LEFT”, 1 );
|
|
Fix( itoa( UPPERLEFT, Buf, 10 ), “UPPERLEFT”, 1 );
|
|
Fix( itoa( LOWERLEFT, Buf, 10 ), “LOWERLEFT”, 1 );
|
|
Fix( itoa( UP, Buf, 10 ), “UP”, 1 );
|
|
Fix( itoa( DOWN, Buf, 10 ), “DOWN”, 1 );
|
|
Fix( itoa( RIGHT, Buf, 10 ), “RIGHT”, 1 );
|
|
Fix( itoa( UPPERRIGHT, Buf, 10 ), “UPPERRIGHT”, 1 );
|
|
Fix( itoa( LOWERRIGHT, Buf, 10 ), “LOWERRIGHT”, New == Old );
|
|
}
|
|
|
|
if( New == Old ) Fix( “0”, “CENTER”, 0 );
|
|
|
|
if( Edge ) printf( “pop si\n” “mov dl,0\n” );
|
|
|
|
Next2();
|
|
}
|
|
|
|
void main( void )
|
|
{
|
|
char *Seg = “ds”;
|
|
|
|
BuildMaps();
|
|
|
|
printf( “DGROUP group _DATA\n” );
|
|
printf( “LIFE segment ‘CODE’\n” );
|
|
printf( “assume cs:LIFE,ds:DGROUP,ss:DGROUP,es:NOTHING\n” );
|
|
printf( “.386C\n” “public _NextGen\n\n” );
|
|
|
|
for( Edge = 0; Edge <= 1; Edge++ )
|
|
{
|
|
for( New = 0; New < 8; New++ )
|
|
{
|
|
for( Old = 0; Old < 8; Old++ )
|
|
{
|
|
if( New != Old ) FirstPass(); Label++;
|
|
SecondPass(); Label++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// finished with first pass
|
|
printf( “org 0\n” );
|
|
printf( “mov si,Change1\n” );
|
|
printf( “mov di,Change2\n” );
|
|
printf( “mov Change1,di\n” );
|
|
printf( “mov Change2,si\n” );
|
|
printf( “mov ChangeCell,0F000h\n” );
|
|
printf( “mov ax,seg _LDMAP\n” );
|
|
printf( “mov ds,ax\n” );
|
|
Next2();
|
|
|
|
// entry point
|
|
printf( “_NextGen: push ds bp si di\n” “cld\n” );
|
|
|
|
if( WIDTH * HEIGHT > LIST_LIMIT ) Seg = “seg _CHANGE”;
|
|
|
|
printf( “mov ax,%s\n”, Seg );
|
|
printf( “mov es,ax\n” );
|
|
|
|
#ifndef NODRAW
|
|
printf( “mov ax,0A000h\n” );
|
|
printf( “mov fs,ax\n” );
|
|
#endif
|
|
|
|
printf( “mov si,Change1\n” );
|
|
printf( “mov dl,0\n” );
|
|
Next1();
|
|
|
|
printf( “LIFE ends\nend\n” );
|
|
}
|
|
</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 © 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 -->
|
|
|
|
|