@@ -2,70 +2,19 @@
#include < stdio.h>
#include < math.h>
// clamp the value x to the range of 0..r
int clamp (int x, int r)
{
if (x < 0 ) return 0 ;
if (x > r) return r;
return x;
}
// generate assembly for the vis table
// the vistable is a 64 kbyte table which stores a precomputed visibility
// info byte for each combination of source and target lightel.
void vistable ()
{
for (unsigned int i = 0 ; i < 256 * 256 ; ++i) {
if ((i & 15 ) == 0 ) printf (" \n .byte " );
if ((i & 15 ) != 0 ) printf (" , " );
int
from_vis = ((i >> 8 ) & 31 ) - 4 ,
to_vis = (i >> 4 ) & 15 ;
int new_vis;
new_vis = clamp (from_vis + to_vis * 2 , 28 ) + 4 ;
printf (" $%02x " , new_vis);
}
printf (" \n\n " );
}
#define LIGHT_RADIUS 21
// assembly snippets for putting together an unrolled
// visibility computation loop
#define LIGHT_ASM \
" lda a:light_origin + $%04x \n " \
" xba\n " \
" lda a:light_origin + $%04x \n " \
" tax\n " \
" lda f:vistable + $%04x , x\n " \
" sta a:light_origin + $%04x \n\n " \
#define SHORT_LIGHT_ASM \
" ;lda a:light_origin + $%04x \n " \
" ;xba\n " \
" lda a:light_origin + $%04x \n " \
" tax\n " \
" lda f:vistable + $%04x , x\n " \
" sta a:light_origin + $%04x \n\n " \
#define COLUMN_ASM \
" cpy #$%02x \n " \
" %s :+\n " \
" jmp %s \n " \
" :\n\n "
// radius of the light
#define RADIUS 23
// number of unrolled loops = BUFFERMAX + 1
#define BUFFERMAX 1
" %s \n " \
" adc a:visibility_origin + $%04x \n " \
" bmi :+\n " \
" jmp _end_tile_%04x \n " \
" :\n " \
" sta a:light_origin + $%04x \n\n "
// get address of a lightel in the bufferpos
@@ -74,22 +23,19 @@ int bufferpos(int xx, int yy)
int p = xx + yy * 32 + 30 * 32 ;
// sanity check
if (p < 0 ) { printf ( " warning: buffer size check failed.\n " ); }
if (p >= 32 * 64 ) { printf ( " warning : buffer size check failed.\n " ); }
if (p < 0 ) { fprintf (stderr, " warning: buffer size check failed.\n " ); }
if (p >= 32 * 64 ) { fprintf (stderr, " warning : buffer size check failed.\n " ); }
return p;
}
// table for the maximum vertical extent
// of each visibility loop variation
int maxtable[] = { -16 , 24 , -24 , 16 };
void tile (int xx, int yy);
// generate the assembly for a single lightel
void light (int xx, int yy, int overflow )
void light (int xx, int yy, int from_xx, int from_yy )
{
if (xx == 0 && yy == 0 ) return ;
@@ -98,8 +44,6 @@ void light(int xx, int yy, int overflow)
int stable[] = { 0 , 1 , 1 , 3 , 1 , 4 , 3 , 7 , 1 , 7 , 4 , 11 , 3 , 10 , 7 , 15 , 1 , 13 , 9 , 19 , 5 , 17 , 11 , 23 };
static int prevxxs = 255 , prevyys = 255 ;
int xxabs = xx < 0 ? -xx : xx;
int yyabs = yy < 0 ? -yy : yy;
@@ -117,91 +61,76 @@ void light(int xx, int yy, int overflow)
} else xxs = xx;
}
if (xxs != from_xx || yys != from_yy) return ;
// get distance from orgin
float rr = sqrtf (xx * xx + yy * yy);
float rrs = sqrtf (xxs * xxs + yys * yys);
int dest = bufferpos (xx, yy);
if (rr > RADIUS + 0 .8f ) {
if (!overflow) return ;
else {
printf (" lda #$ff\n " );
printf (" sta a:light_origin + $%04x \n " , dest);
return ;
}
}
if (rr > LIGHT_RADIUS) return ;
printf ((prevxxs == xxs && prevyys == yys) ? SHORT_LIGHT_ASM : LIGHT_ASM,
printf (LIGHT_ASM,
bufferpos (xxs, yys),
dest,
(int )(rr * 0 .8f ) == (int )(rrs * 0 .8f ) ? 0x0 : 0x100 ,
dest);
(int )(rr * 0 .8f ) == (int )(rrs * 0 .8f ) ? " clc" : " sec" ,
bufferpos (xxs, yys), yy * 256 + xx, dest);
tile (xx, yy); // recursively build the shadow cone
prevxxs = xxs;
prevyys = yys;
printf (" _end_tile_%04x :\n " , yy * 256 + xx);
}
void tile (int xx, int yy)
{
light (xx - 1 , yy - 1 , xx, yy);
light (xx , yy - 1 , xx, yy);
light (xx + 1 , yy - 1 , xx, yy);
light (xx - 1 , yy , xx, yy);
light (xx + 1 , yy , xx, yy);
light (xx - 1 , yy + 1 , xx, yy);
light (xx , yy + 1 , xx, yy);
light (xx + 1 , yy + 1 , xx, yy);
}
// generate a visibility computation loop
void cast (int ii)
// make a fence around the visibile area
// for aborting the loop
void fence ()
{
printf (" viscast_%i :\n " , ii);
for (int xx = 0 ; xx >= -RADIUS; --xx) {
for (int yy = 0 ; yy >= -RADIUS; --yy)
if (yy >= maxtable[(BUFFERMAX - ii) * 2 + 0 ]) light (xx, yy, 0 );
for (int yy = 1 ; yy <= RADIUS; ++yy)
if (yy < maxtable[(BUFFERMAX - ii) * 2 + 1 ]) light (xx, yy, 0 );
if (xx > -RADIUS) printf (COLUMN_ASM, (32 + xx) * 2 , " bmi" , " @skip_1" );
printf (" lda #31\n " );
for (int ii = 0 ; ii < 32 ; ++ii) {
printf (" sta a:visibility_origin + $%04x , x\n " , ii);
printf (" sta a:visibility_origin + $%04x , x\n " , ii + 32 * 29 );
}
printf (" @skip_1:\n\n " );
for (int xx = 1 ; xx <= RADIUS; ++xx) {
for (int yy = 0 ; yy >= -RADIUS; --yy)
if (yy >= maxtable[(BUFFERMAX - ii) * 2 + 0 ]) light (xx, yy, 0 );
for (int yy = 1 ; yy <= RADIUS; ++yy)
if (yy < maxtable[(BUFFERMAX - ii) * 2 + 1 ]) light (xx, yy, 0 );
if (xx < RADIUS) printf (COLUMN_ASM, (xx + 2 ) * 2 , " bpl" , " _end" );
for (int ii = 0 ; ii < 30 ; ++ii) {
printf (" sta a:visibility_origin + $%04x , x\n " , ii * 32 );
printf (" sta a:visibility_origin + $%04x , x\n " , ii * 32 + 31 );
}
printf (" jmp _end\n\n " );
}
// generate the visibility computation loop
int main ()
{
printf (" .export viscast\n " );
printf (" .import light_origin \n\n " );
printf (" .import visibility_origin \n\n " );
printf (" .segment \" code3\"\n\n " );
printf (" jumptable:\n\n " );
printf (" .word .loword(viscast_0)\n " );
printf (" .word .loword(viscast_1)\n " );
printf (" \n viscast:\n\n " );
printf (" lda #$7e\n pha\n plb\n\n " );
printf (" jmp (.loword(jumptable), x)\n\n " );
printf (" _end:\n\n " );
printf (" lda #$80\n pha\n plb\n\n " );
printf (" rtl\n\n " );
for (int ii = 0 ; ii <= BUFFERMAX; ++ii) {
cast (ii);
}
printf (" \n\n .segment \" vistable\"\n\n " );
printf ( " \n vistable: \n " );
fence ( );
vistable ( );
tile ( 0 , 0 );
printf (" _end:\n\n " );
printf (" lda #$80\n pha\n plb\n\n " );
printf (" rtl\n\n " );
return 0 ;
};