These videos might hang your browser, sorry!
Flight Simulator
//$FG,2$This might get turned into a game where you are an Eagle$FG$
//$FG,2$and you dive for fish.$FG$



//$FG,2$Keep these power of two so shift is used instead of multiply$FG$
//$FG,2$to index arrays.$FG$
#define MAP_WIDTH                1024
#define MAP_HEIGHT                1024

#define MAP_SCALE                150
#define DISPLAY_SCALE                100
#define CONTROLS_SCALE                0.05

//$FG,2$I think I did these so the heads-up showed intelligable numbers.$FG$
//$FG,2$Scaling is a mess.$FG$
#define COORDINATE_SCALE        256
#define COORDINATE_BITS                8

#define WATER_ELEVATION                15
#define ROCK_ELEVATION                45
#define SNOW_ELEVATION                55

//$FG,2$Too big makes off-screen draws take place.$FG$
#define MAX_PANEL_SIZE                16

class Panel
{
 Panel *next;
 I4 n,   //num polygon sides
       num; //panel number
 P3I4 *points;
 I8 color;
};

//$FG,2$These are not deallocated after the program ends,$FG$
//$FG,2$but I did them this way for your benefit$FG$
//$FG,2$so 2D array indexing is not done by hand.$FG$
//$FG,2$You can type "FlightSim2;" at the command line$FG$
//$FG,2$to rerun without new allocations.$FG$
//$FG,2$Normally, just spawn a popup task,$FG$
//$FG,2$run it and kill it using an icon.$FG$
I2 elevations[MAP_HEIGHT][MAP_WIDTH];
Panel *panels[MAP_HEIGHT][MAP_WIDTH];
Panel *panels_hstep[MAP_HEIGHT][MAP_WIDTH];
Panel *panels_vstep[MAP_HEIGHT][MAP_WIDTH];

I8 num_panels;
Panel *panel_root;
U1 *panels_processed_bitmap;

double
 phi        =-90.0*pi/180.0,
 theta1=  0.0*pi/180.0,
 theta2=  0.0*pi/180.0,
 speed =  1.5;

I8 x=MAP_WIDTH>>1 *COORDINATE_SCALE*MAP_SCALE,
   y=MAP_HEIGHT>>1*COORDINATE_SCALE*MAP_SCALE,
   z=64            *COORDINATE_SCALE*MAP_SCALE;

BoolI1 crashed=FALSE;
double grid_size=64.0;

class MPCtrl {
 double phi,theta1,theta2,grid_size;
 I8 x,y,z;
 TssStruct *win_tss;
 BoolI1 update,done;
 GrBitMap *base;
};

void FSTransform(GrBitMap *base,I8 *x,I8 *y,I8 *z)
{
//$FG,2$I accidentally made the Z coordinate sign backward$FG$
//$FG,2$from the fill-poly depth buffer scheme, so it is negated at the end.$FG$
//$FG,2$Negative Z coordinates are the ones we want plotted.$FG$
 GrRotate(base->r,x,y,z);

//$FG,2$We don't want divide by zero or make too monstrous foreground objects.$FG$
//$FG,2$The foreground object boundry is kinda crappy looking when$FG$
//$FG,2$you point toward the ground.$FG$
 if (*z<-50) {

//$FG,2$The divide causes "foreshortening" which makes the distance go to a vanishing point.$FG$
     *x = *x * -DISPLAY_SCALE/ *z;
     *y = *y * -DISPLAY_SCALE/ *z;
 }
 *x+=base->x;
 *y=base->y-*y;
 *z=-*z;
}


BoolI8 TestFlat(I8 x,I8 y,I8 w,I8 h)
{
 I8 s,k1,k2,xx,yy;
 if (!(0<=x && x+w<=MAP_WIDTH && 0<=y && y+h<=MAP_HEIGHT))
     return FALSE;
 s=elevations[y][x];
 for (k2=0;k2<h;k2++)
     for (k1=0;k1<w;k1++) {
         xx=x+k1;
         yy=y+k2;
         if (panels[yy][xx] || elevations[yy][xx]!=s)
             return FALSE;
     }
 return TRUE;
}

BoolI8 TestHSlope(I8 x,I8 y,I8 w,I8 h)
{
 I8 k1,k2,xx,yy,s;
 if (!(0<=x && x+w<=MAP_WIDTH && 0<=y && y+h<MAP_HEIGHT) ||
       !(s=SignI8(elevations[y+1][x]-elevations[y][x])))
     return FALSE;
 for (k2=0;k2<h;k2++)
     for (k1=0;k1<w;k1++) {
         xx=x+k1;
         yy=y+k2;
         if (panels[yy][xx] ||
             SignI8(elevations[yy+1][xx]-elevations[yy][xx])!=s)
             return FALSE;
     }
 return TRUE;
}

BoolI8 TestVSlope(I8 x,I8 y,I8 w,I8 h)
{
 I8 k1,k2,xx,yy,s;
 if (!(0<=x && x+w<MAP_WIDTH && 0<=y && y+h<=MAP_HEIGHT) ||
       !(s=SignI8(elevations[y][x+1]-elevations[y][x])))
     return FALSE;
 for (k2=0;k2<h;k2++)
     for (k1=0;k1<w;k1++) {
         xx=x+k1;
         yy=y+k2;
         if (panels[yy][xx] ||
             SignI8(elevations[yy][xx+1]-elevations[yy][xx])!=s)
             return FALSE;
     }
 return TRUE;
}

BoolI8 TestHStep(I8 x,I8 y,I8 w)
{
 I8 k1,i,s;
 if (!(0<=x && x+w<=MAP_WIDTH && 0<=y && y+1<MAP_HEIGHT) ||
         !(s=SignI8(elevations[y+1][x]-(i=elevations[y][x]))))
     return FALSE;
 for (k1=0;k1<w;k1++) {
     if (panels_vstep[y][x] ||
         elevations[y][x]!=i ||
         SignI8(elevations[y+1][x]-i)!=s)
         return FALSE;
     x++;
 }
 return TRUE;
}

BoolI8 TestVStep(I8 x,I8 y,I8 h)
{
 I8 k2,i,s;
 if (!(0<=x && x+1<MAP_WIDTH && 0<=y && y+h<=MAP_HEIGHT) ||
         !(s=SignI8(elevations[y][x+1]-(i=elevations[y][x]))))
     return FALSE;
 for (k2=0;k2<h;k2++) {
     if (panels_vstep[y][x] ||
         elevations[y][x]!=i ||
         SignI8(elevations[y][x+1]-i)!=s)
         return FALSE;
     y++;
 }
 return TRUE;
}

void InitMap()
{
//$FG,2$We make a topographic data structure "evevations[][]"$FG$
//$FG,2$and convert it to panels.  The conversion to panels leaves$FG$
//$FG,2$gaps the way I did it, but it looks good, except for sky leaking through$FG$
//$FG,2$There is no wrong way to pick colors if it looks good, unless$FG$
//$FG,2$you wanted to do lighting.$FG$

//$FG,2$"panels[][]" holds the flat and sloped panels for each spot, while$FG$
//$FG,2$"hstep_panels[][]" holds side panels in cases of step-like formations.$FG$
//$FG,2$They require a separate array because a single "elevation[][]" spot can$FG$
//$FG,2$have a panel on top and a panel on the side like stairs.$FG$

 I8 i,j,l,k1,k2,x,y,xx,yy,w,h,threshold;
 BoolI1 cont;
 Panel *tempp;
 P3I4 *p;
 MemSet(elevations,0,sizeof(elevations));
 MemSet(panels,0,sizeof(panels));
 MemSet(panels_hstep,0,sizeof(panels_hstep));
 MemSet(panels_vstep,0,sizeof(panels_vstep));
 for (i=0;i<MAP_WIDTH*MAP_HEIGHT/128;i++) {
     x=RandU4%MAP_WIDTH;
     y=RandU4%MAP_HEIGHT;
     j=1<<(RandU4%6);
     l=0;
     while (j--) {
         if (!l && RandU2<MAX_U2/4)
             l=RandU2%(j+1);
         if (l) {
             for (k1=-j;k1<=j;k1++)
                 for (k2=-j;k2<=j;k2++) {
                     xx=x+k2; yy=y+k1;
                     if (0<=xx<MAP_WIDTH &&
                             0<=yy<MAP_HEIGHT)
                         elevations[yy][xx]+=MAP_SCALE/2;
                 }
                 l--;
         }
     }
 }
 xx=x/(MAP_SCALE*COORDINATE_SCALE);
 yy=y/(MAP_SCALE*COORDINATE_SCALE);
 z+=elevations[yy][xx]*COORDINATE_SCALE;

 for (j=0;j<MAP_HEIGHT;j++)
     for (i=0;i<MAP_WIDTH;i++)
         if (elevations[j][i]<WATER_ELEVATION*MAP_SCALE)
             elevations[j][i]=WATER_ELEVATION*MAP_SCALE;

 panel_root=NULL;
 num_panels=0;

 for (threshold=8;threshold>1;threshold--)
     for (j=0;j<MAP_HEIGHT;j++)
         for (i=0;i<MAP_WIDTH;i++) {
             if (!panels[j][i]) {
                 w=1;
                 h=1;
                 do {
                     cont=FALSE;
                     if (w<MAX_PANEL_SIZE && TestFlat(i,j,w+1,h)) {
                         w++;
                         cont=TRUE;
                     }
                     if (h<MAX_PANEL_SIZE && TestFlat(i,j,w,h+1)) {
                         h++;
                         cont=TRUE;
                     }
                 } while (cont);
                 if (w>=threshold || h>=threshold) {
                     tempp=MAlloc(sizeof(Panel));
                     tempp->num=num_panels++;
                     if (elevations[j][i]<=WATER_ELEVATION*MAP_SCALE)
                         tempp->color=BLUE;
                     else if (elevations[j][i]<ROCK_ELEVATION*MAP_SCALE)
                         tempp->color=LTGREEN;
                     else if (elevations[j][i]<SNOW_ELEVATION*MAP_SCALE) {
                         if (!(RandU2&3))
                             tempp->color=LTGRAY;
                         else
                             tempp->color=LTGREEN;
                     } else {
                         if (!(RandU2&3))
                             tempp->color=WHITE;
                         else
                             tempp->color=LTGRAY;
                     }
                     tempp->n=4;
                     p=tempp->points=MAlloc(sizeof(P3I4)*tempp->n);
                     l=elevations[j][i];
                     p[0].x=MAP_SCALE*i;
                     p[0].y=MAP_SCALE*j;
                     p[0].z=l;
                     p[1].x=MAP_SCALE*(i+w);
                     p[1].y=MAP_SCALE*j;
                     p[1].z=l;
                     p[2].x=MAP_SCALE*(i+w);
                     p[2].y=MAP_SCALE*(j+h);
                     p[2].z=l;
                     p[3].x=MAP_SCALE*i;
                     p[3].y=MAP_SCALE*(j+h);
                     p[3].z=l;
                     tempp->next=panel_root;
                     panel_root=tempp;
                     for (k2=0;k2<h;k2++)
                         for (k1=0;k1<w;k1++)
                             panels[j+k2][i+k1]=tempp;
                 }
             }
         }
 for (threshold=8;threshold>1;threshold--) {
     for (j=0;j<MAP_HEIGHT-1;j++)
         for (i=0;i<MAP_WIDTH-1;i++) {
             if (!panels[j][i]) {
                 w=1;
                 h=1;
                 do {
                     cont=FALSE;
                     if (w<MAX_PANEL_SIZE && TestHSlope(i,j,w+1,h)) {
                         w++;
                         cont=TRUE;
                     }
                     if (h<MAX_PANEL_SIZE && TestHSlope(i,j,w,h+1)) {
                         h++;
                         cont=TRUE;
                     }
                 } while (cont);
                 if (w>=threshold || h>=threshold) {
                     tempp=MAlloc(sizeof(Panel));
                     tempp->num=num_panels++;
                     if (elevations[j][i]<ROCK_ELEVATION*MAP_SCALE)
                         tempp->color=GREEN;
                     else if (elevations[j][i]<SNOW_ELEVATION*MAP_SCALE) {
                         if (!(RandU2&3))
                             tempp->color=DKGRAY;
                         else
                             tempp->color=GREEN;
                     } else {
                         if (!(RandU2&3))
                             tempp->color=LTGRAY;
                         else
                             tempp->color=DKGRAY;
                     }
                     tempp->n=4;
                     p=tempp->points=MAlloc(sizeof(P3I4)*tempp->n);
                     p[0].x=MAP_SCALE*i;
                     p[0].y=MAP_SCALE*j;
                     p[0].z=elevations[j][i];
                     p[1].x=MAP_SCALE*(i+w);
                     p[1].y=MAP_SCALE*j;
                     p[1].z=elevations[j][i+w-1];
                     p[2].x=MAP_SCALE*(i+w);
                     p[2].y=MAP_SCALE*(j+h+1);
                     p[2].z=elevations[j+h][i+w-1];
                     p[3].x=MAP_SCALE*i;
                     p[3].y=MAP_SCALE*(j+h+1);
                     p[3].z=elevations[j+h][i];
                     tempp->next=panel_root;
                     panel_root=tempp;
                     for (k2=0;k2<h;k2++)
                         for (k1=0;k1<w;k1++)
                             panels[j+k2][i+k1]=tempp;
                 } else {
                     w=1;
                     h=1;
                     do {
                         cont=FALSE;
                         if (w<MAX_PANEL_SIZE && TestVSlope(i,j,w+1,h)) {
                             w++;
                             cont=TRUE;
                         }
                         if (h<MAX_PANEL_SIZE && TestVSlope(i,j,w,h+1)) {
                             h++;
                             cont=TRUE;
                         }
                     } while (cont);
                     if (w>=threshold || h>=threshold) {
                         tempp=MAlloc(sizeof(Panel));
                         tempp->num=num_panels++;
                         if (elevations[j][i]<ROCK_ELEVATION*MAP_SCALE)
                             tempp->color=GREEN;
                         else if (elevations[j][i]<SNOW_ELEVATION*MAP_SCALE) {
                             if (!(RandU2&3))
                                 tempp->color=DKGRAY;
                             else
                                 tempp->color=GREEN;
                         } else {
                             if (!(RandU2&3))
                                 tempp->color=LTGRAY;
                             else
                                 tempp->color=DKGRAY;
                         }
                         tempp->n=4;
                         p=tempp->points=MAlloc(sizeof(P3I4)*tempp->n);
                         p[0].x=MAP_SCALE*i;
                         p[0].y=MAP_SCALE*j;
                         p[0].z=elevations[j][i];
                         p[1].x=MAP_SCALE*(i+w+1);
                         p[1].y=MAP_SCALE*j;
                         p[1].z=elevations[j][i+w];
                         p[2].x=MAP_SCALE*(i+w+1);
                         p[2].y=MAP_SCALE*(j+h);
                         p[2].z=elevations[j+h-1][i+w];
                         p[3].x=MAP_SCALE*i;
                         p[3].y=MAP_SCALE*(j+h);
                         p[3].z=elevations[j+h-1][i];
                         tempp->next=panel_root;
                         panel_root=tempp;
                         for (k2=0;k2<h;k2++)
                             for (k1=0;k1<w;k1++)
                                 panels[j+k2][i+k1]=tempp;
                     }
                 }
             }
         }
 }
 for (j=0;j<MAP_HEIGHT;j++)
     for (i=0;i<MAP_WIDTH;i++) {
         if (!panels_hstep[j][i]) {
             w=1;
             while (w<MAX_PANEL_SIZE && TestHStep(i,j,w+1))
                 w++;
             if (w>=2) {
                 tempp=MAlloc(sizeof(Panel));
                 tempp->num=num_panels++;
                 if (elevations[j][i]<ROCK_ELEVATION*MAP_SCALE)
                     tempp->color=GREEN+LTGREEN<<32+ROP_DITHER;
                 else if (elevations[j][i]<SNOW_ELEVATION*MAP_SCALE) {
                     if (!(RandU2&3))
                         tempp->color=DKGRAY+LTGRAY<<32+ROP_DITHER;
                     else
                         tempp->color=GREEN+LTGREEN<<32+ROP_DITHER;
                 } else {
                     if (!(RandU2&3))
                         tempp->color=LTGRAY+WHITE<<32+ROP_DITHER;
                     else
                         tempp->color=DKGRAY+LTGRAY<<32+ROP_DITHER;
                 }
                 tempp->n=4;
                 p=tempp->points=MAlloc(sizeof(P3I4)*tempp->n);
                 p[0].x=MAP_SCALE*i;
                 p[0].y=MAP_SCALE*j;
                 p[0].z=elevations[j][i];
                 p[1].x=MAP_SCALE*i;
                 p[1].y=MAP_SCALE*(j+1);
                 p[1].z=elevations[j+1][i];
                 p[2].x=MAP_SCALE*(i+w);
                 p[2].y=MAP_SCALE*(j+1);
                 p[2].z=elevations[j+1][i+w-1];
                 p[3].x=MAP_SCALE*(i+w);
                 p[3].y=MAP_SCALE*j;
                 p[3].z=elevations[j][i+w-1];
                 tempp->next=panel_root;
                 panel_root=tempp;
                 for (k1=0;k1<w;k1++)
                     panels_hstep[j][i+k1]=tempp;
             }
         }
         if (!panels_vstep[j][i]) {
             h=1;
             while (h<MAX_PANEL_SIZE && TestVStep(i,j,h+1))
                 h++;
             if (h>=2) {
                 tempp=MAlloc(sizeof(Panel));
                 tempp->num=num_panels++;
                 if (elevations[j][i]<ROCK_ELEVATION*MAP_SCALE)
                     tempp->color=GREEN+LTGREEN<<32+ROP_DITHER;
                 else if (elevations[j][i]<SNOW_ELEVATION*MAP_SCALE) {
                     if (!(RandU2&3))
                         tempp->color=DKGRAY+LTGRAY<<32+ROP_DITHER;
                     else
                         tempp->color=GREEN+LTGREEN<<32+ROP_DITHER;
                 } else {
                     if (!(RandU2&3))
                         tempp->color=LTGRAY+WHITE<<32+ROP_DITHER;
                     else
                         tempp->color=DKGRAY+LTGRAY<<32+ROP_DITHER;
                 }
                 tempp->n=4;
                 p=tempp->points=MAlloc(sizeof(P3I4)*tempp->n);
                 p[0].x=MAP_SCALE*i;
                 p[0].y=MAP_SCALE*j;
                 p[0].z=elevations[j][i];
                 p[1].x=MAP_SCALE*(i+1);
                 p[1].y=MAP_SCALE*j;
                 p[1].z=elevations[j][i+1];
                 p[2].x=MAP_SCALE*(i+1);
                 p[2].y=MAP_SCALE*(j+h);
                 p[2].z=elevations[j+h-1][i+1];
                 p[3].x=MAP_SCALE*i;
                 p[3].y=MAP_SCALE*(j+h);
                 p[3].z=elevations[j+h-1][i];
                 tempp->next=panel_root;
                 panel_root=tempp;
                 for (k2=0;k2<h;k2++)
                     panels_vstep[j+k2][i]=tempp;
             }
         }
     }
 panels_processed_bitmap=MAlloc((num_panels+7)>>3);
}

void UpdateWin(TssStruct *tss)
{
/*$FG,2$
This core#0 renders the far scenery, the $FG,11$LTBLUE$FG,2$ on this
diagram. The other core, #1, and other update routine renders the
near, $FG,10$LTGREEN$FG,2$. The persistent layer for core#1 is merged
(using a mask telling what has been plotted) on
top of the nonpersistent layer for core#0, so we use
it for the foreground.        Depth buffers are not shared, so
I think we could get glitches.        We actually could probably
get decent results without depth buffers since we could
render from back to front.  We render from front to back, however.
The size of the rendered area is adjusted based on utilizing
the whole CPU.        This routine for core#0 renders until the other
core finishes.        Core #1 must be kept synched, so we let it drive, so to speak.
Core zero renders foreshortend distant polygons which are smaller and would
finsish faster, which would create problems, so we let it render off into
the distance until core #1 finishes.$FG$



$PI,"",1$












*/


 I8 i,ww,*r,*r1,*r2,*r3,*r4, x1,y1,z1, xx,yy,
         xh,yh,zh, x1w,y1w, x1h,y1h, grid_s,
         cx=tss->win_pixel_width>>1,
         cy=tss->win_pixel_height>>1,height;
 MPCtrl *mp=tss->mp;
 double d;
 GrBitMap *base=GrAlias(grbase,tss);
 Panel *tempp;

 GrAllocDepthBuffer(base);

 //Adjust grid size to utilize whole CPU power
 d=Limit(1.05*win_actual_refresh/win_max_refresh,0.666666,1.5);
 grid_size*=0.9+0.1*d;
 if (grid_size<10.0)
     grid_size=10.0;
 grid_s=grid_size;

//$FG,2$"panels_processed_bitmap" is in cache and is not kept consistent$FG$
//$FG,2$with the other core, but errors just cause panels to be drawn twice.$FG$

//$FG,2$"mp" is uncached so it is good for communicating between cores.$FG$
//$FG,2$it was allocated from the 2Meg "mp_heap".$FG$
 MemSet(panels_processed_bitmap,0,(num_panels+7)>>3);
 mp->phi=phi;
 mp->theta1=theta1;
 mp->theta2=theta2;
 mp->x=x;
 mp->y=y;
 mp->z=z;
 mp->update=TRUE;
 mp->grid_size=grid_size;


 xx=x/(MAP_SCALE*COORDINATE_SCALE);
 yy=y/(MAP_SCALE*COORDINATE_SCALE);
 height=z/COORDINATE_SCALE-elevations[yy][xx];
 if (height<0) {
     if (!crashed) {
         music_mute=TRUE;
         Sound(1000); //Signal plane crashed
         crashed=TRUE;
     }
 } else {
     if (crashed) {
         Sound(0);
         music_mute=FALSE;
         crashed=FALSE;
     }
 }

 base->color=BLACK;
 GrPrintF(base,0,0,"Theta1:%5.1f Phi:%5.1f Theta2:%5.1f Box:%5.1f",
         theta1*180/pi,phi*180/pi,theta2*180/pi,grid_size);
 GrPrintF(base,0,FONT_HEIGHT,"x:%5.1f y:%5.1f z:%5.1f height:%3d",
         ToDouble(x)/COORDINATE_SCALE,ToDouble(y)/COORDINATE_SCALE,ToDouble(z)/COORDINATE_SCALE,
         height);

 //$FG,2$World to screen coordinates$FG$
 r1=GrRotZ(theta1);
 r2=GrRotX(phi);
 r3=GrRotZ(theta2);
 r4=GrMulMat(r1,r2);
 Free(base->r);
 base->r=GrMulMat(r4,r3);
 Free(r1);
 Free(r2);
 Free(r3);
 Free(r4);

 //$FG,2$Screen to world coordinates$FG$

//$FG,2$This gives us the vectors for stepping through the grid in$FG$
//$FG,2$the direction the plane is facing. we step horizontally and vertically$FG$
//$FG,2$and use the reciprocal slope principle        y=mx+b and y=(-1/m)x+b are perpendicular.$FG$

 r1=GrRotZ(-theta2);
 r2=GrRotX(-phi);
 r3=GrRotZ(-theta1);
 r4=GrMulMat(r1,r2);
 r=GrMulMat(r4,r3);
 xh=0;
 yh=0;
 zh=-65536;
 GrRotate(r,&xh,&yh,&zh);
 if (i=ToI8(Sqrt(xh*xh+yh*yh))>>8) {
     xh/=i;
     yh/=i;
 } else {
     xh=256;
     yh=0;
 }

 Free(r1);
 Free(r2);
 Free(r3);
 Free(r4);
 Free(r);

 base->flags|=BMF_TRANSFORMATION;
 base->transform=&FSTransform;
 base->x=cx;
 base->y=cy;

//$FG,2$base->x and the translation part of base->r are identical in effect,$FG$
//$FG,2$but we use both to show-off.        We could add offsets together and use one or the other.$FG$

 x1=-x>>COORDINATE_BITS;
 y1=-y>>COORDINATE_BITS;
 z1=-z>>COORDINATE_BITS;
 GrRotate(base->r,&x1,&y1,&z1);
 GrSetTranslation(base->r,x1,y1,z1);


 ww=grid_s*8;
 x1h=xx<<8+yh*grid_s*2+xh*grid_s/2;
 y1h=yy<<8-xh*grid_s*2+yh*grid_s/2;
 xh>>=1; yh>>=1;
 while (mp->update) {
     x1w=x1h;
     y1w=y1h;
     for (i=0;i<ww;i++) {
         x1=x1w>>8; y1=y1w>>8;
         if (0<=x1<MAP_WIDTH && 0<=y1<MAP_HEIGHT) {
                 if ((tempp=panels[y1][x1]) && !Bts(panels_processed_bitmap,tempp->num)) {
                     base->color=tempp->color;
                     GrFillPolygon3(base,tempp->n,tempp->points);
                 }
                 if ((tempp=panels_hstep[y1][x1]) && !Bts(panels_processed_bitmap,tempp->num)) {
                     base->color=tempp->color;
                     GrFillPolygon3(base,tempp->n,tempp->points);
                 }
                 if ((tempp=panels_vstep[y1][x1]) && !Bts(panels_processed_bitmap,tempp->num)) {
                     base->color=tempp->color;
                     GrFillPolygon3(base,tempp->n,tempp->points);
                 }
         }
         x1w-=yh;
         y1w+=xh;
     }
     x1h+=xh;
     y1h+=yh;
 }
 base->pen_width=2;
 base->color=BLACK;
 base->flags&=~BMF_TRANSFORMATION;
 GrLine3(base,cx+5,cy,0,cx-5,cy,0);
 GrLine3(base,cx,cy+5,0,cx,cy-5,0);


 GrDel(base);
}


void MPDrawIt(MPCtrl *mp)
{
//$FG,2$This is identical to the previous routine but is run by core#1$FG$

 TssStruct *tss=mp->win_tss;
 I8 i,j,ww,*r,*old_r,*r1,*r2,*r3,*r4, x1,y1,z1, xx,yy,
         xh,yh,zh, x1w,y1w, x1h,y1h,
         cx=tss->win_pixel_width>>1,
         cy=tss->win_pixel_height>>1;
 GrBitMap *base=mp->base;
 I8 x=mp->x,y=mp->y,z=mp->z,grid_s=mp->grid_size;
 Panel *tempp;

//$FG,2$The base we used is not reallocated each time because we don't have room$FG$
//$FG,2$for a depth buffer in the default core#1 heap which is only 2 Meg.  I could$FG$
//$FG,2$increase the default heap size for all cores, but you guys may as get used$FG$
//$FG,2$to dealing with a limited heap for other cores.  "base" is allocated in the$FG$
//$FG,2$main routine and used over and over without deallocating and reallocating.$FG$

//$FG,2$If you like, you can create an independent heap by removing blocks from$FG$
//$FG,2$the main core#0 heap with $LK,"Alloc2MegMemBlks","MN:Alloc2MegMemBlks"$() or $LK,"
AllocUncachedMemBlks","MN:AllocUncachedMemBlks"$(),$FG$
//$FG,2$supply the core#0 block pool Gs->data_bp.$FG$
//$FG,2$setting up an independent heap with $LK,"InitIndependentHeapCtrl","MN:InitIndependentHeapCtrl"$()
and using$FG$
//$FG,2$$LK,"MAllocHC","MN:MAllocHC"$() to malloc from a specified heap control structure.$FG$

//$FG,2$If you have memory beyond 2gig, it's not being used.        Supply a raw$FG$
//$FG,2$absolute address to $LK,"InitIndependentHeapCtrl","MN:InitIndependentHeapCtrl"$() and go merily on
your way.$FG$
//$FG,2$You might want to adjust the core#0 data_bp block pool to utilize it.$FG$
//$FG,2$Figure-it out yourself -- see $LK,"Memory","HI:Memory"$.$FG$

 base->win_tss=tss;
 GrResetDepthBuffer(base);

//$FG,2$This is not kept consistent with core#0 but causes no serious problems.$FG$
 MemSet(panels_processed_bitmap,0,(num_panels+7)>>3);
 xx=x/(MAP_SCALE*COORDINATE_SCALE);
 yy=y/(MAP_SCALE*COORDINATE_SCALE);

 //$FG,2$World to screen coordinates$FG$
 r1=GrRotZ(mp->theta1);
 r2=GrRotX(mp->phi);
 r3=GrRotZ(mp->theta2);
 r4=GrMulMat(r1,r2);
 old_r=base->r;
 base->r=GrMulMat(r4,r3);
 Free(r1);
 Free(r2);
 Free(r3);
 Free(r4);

 //$FG,2$Screen to world coordinates$FG$

//$FG,2$This gives us the vectors for stepping through the grid in$FG$
//$FG,2$the direction the plane is facing. we step horizontally and vertically$FG$
//$FG,2$and use the reciprocal slope principle        y=mx+b and y=(-1/m)x+b are perpendicular.$FG$

 r1=GrRotZ(-mp->theta2);
 r2=GrRotX(-mp->phi);
 r3=GrRotZ(-mp->theta1);
 r4=GrMulMat(r1,r2);
 r=GrMulMat(r4,r3);
 xh=0;
 yh=0;
 zh=-65536;
 GrRotate(r,&xh,&yh,&zh);
 if (i=ToI8(Sqrt(xh*xh+yh*yh))>>8) {
     xh/=i;
     yh/=i;
 } else {
     xh=256;
     yh=0;
 }

//$FG,2$The layer for core#1 is not cleared automatically$FG$
//$FG,2$it is persistent.  I have carefully syncronized to the update$FG$
//$FG,2$cycle initiated by core#0 to prevent flicker.$FG$

 GrClear(base);

 Free(r1);
 Free(r2);
 Free(r3);
 Free(r4);
 Free(r);

 base->flags|=BMF_TRANSFORMATION;
 base->transform=&FSTransform;
 base->x=cx;
 base->y=cy;

//$FG,2$base->x and the translation part of base->r are identical in effect,$FG$
//$FG,2$but we use both to show-off.        We could add offsets together and use one or the other.$FG$

 x1=-x>>COORDINATE_BITS;
 y1=-y>>COORDINATE_BITS;
 z1=-z>>COORDINATE_BITS;
 GrRotate(base->r,&x1,&y1,&z1);
 GrSetTranslation(base->r,x1,y1,z1);

 ww=grid_s*8;
 x1h=xx<<8+yh*grid_s*2;
 y1h=yy<<8-xh*grid_s*2;
 xh>>=1; yh>>=1;
 for (j=0;j<grid_s;j++) {
     x1w=x1h;
     y1w=y1h;
     for (i=0;i<ww;i++) {
         x1=x1w>>8; y1=y1w>>8;
         if (0<=x1<MAP_WIDTH && 0<=y1<MAP_HEIGHT) {
                 if ((tempp=panels[y1][x1]) && !Bts(panels_processed_bitmap,tempp->num)) {
                     base->color=tempp->color;
                     GrFillPolygon3(base,tempp->n,tempp->points);
                 }
                 if ((tempp=panels_hstep[y1][x1]) && !Bts(panels_processed_bitmap,tempp->num)) {
                     base->color=tempp->color;
                     GrFillPolygon3(base,tempp->n,tempp->points);
                 }
                 if ((tempp=panels_vstep[y1][x1]) && !Bts(panels_processed_bitmap,tempp->num)) {
                     base->color=tempp->color;
                     GrFillPolygon3(base,tempp->n,tempp->points);
                 }
         }
         x1w-=yh;
         y1w+=xh;
     }
     x1h+=xh;
     y1h+=yh;
 }
 base->r=old_r;
}

void MPUpdateTask(MPCtrl *mp)
{
 while (!mp->done) {
     while (!mp->update && !mp->done)
         SwapInNextTask;
     MPDrawIt(mp);
     mp->update=FALSE;
 }
 GrClear(Gs->grbase);
 mp->done=FALSE;
}

void AnimateTask()
{
//$FG,2$This just steadily moves the airplane forward.$FG$
 I8 *r1,*r2,*r3,*r4,*r,x1,y1,z1;
 while (TRUE) {

 //$FG,2$Screen to world coordinates$FG$
     r1=GrRotZ(-theta2);
     r2=GrRotX(-phi);
     r3=GrRotZ(-theta1);
     r4=GrMulMat(r1,r2);
     r=GrMulMat(r4,r3);

     x1=0;y1=0;z1=-speed*COORDINATE_SCALE;
     GrRotate(r,&x1,&y1,&z1);
     x+=x1;
     y+=y1;
     z+=z1;
     Free(r1);
     Free(r2);
     Free(r3);
     Free(r4);
     Free(r);
     Sleep(1);
 }
}

void PanelsDel()
{
 Panel *tempp=panel_root,*tempp1;
 while (tempp) {
     tempp1=tempp->next;
     Free(tempp->points);
     Free(tempp);
     tempp=tempp1;
 }
 Free(panels_processed_bitmap);
}

void MPEnd(MPCtrl *mp)
{
 mp->done=TRUE;
 while (mp->done)
     SwapInNextTask;
 Free(mp);
}

void EndTaskCB()
{
 //$FG,2$We need this to shut-down CPU#1 task$FG$
 //$FG,2$in case of CPU0 task getting terminated$FG$
 //$FG,2$irregularly. CTRL-ALT-X or Kill()$FG$
 MPEnd(Fs->mp);
 Fs->mp=NULL;
 Exit;
}

void SongTask()
{
 Fs->end_task_cb=&SoundEndTaskCB;
 MusicResetSettings;
 music_stacatto_factor=0.2;
 while (TRUE) {
     Play("W13eBDEDBDEDFEEDFEED");
     Play("BDEDBDEDFEEDFEED");
 }
}

void FlightSim2()
{
 I8 ch,sc;
 double pp,tt1,tt2;
 void *old_update=Fs->update_win;
 TssStruct *animate_tss,*song_tss;
 BoolI1 old_wordstat=WordStat(OFF);
 double old_refresh=win_max_refresh;
 MPCtrl *mp;
 I8 old_attr=Fs->text_attr;

//$FG,2$We really can't afford to run at 60Hz.        This is how often VGA$FG$
//$FG,2$memory is updated, not related to actual hardware refresh rates.$FG$
 win_max_refresh=12.0;

 WinMax;
 coutln "$$BG,LTCYAN$$Initializing...";
 InitMap;

 animate_tss=Spawn(&AnimateTask,0,"FSim2 Animate",Fs);
 song_tss=Spawn(&SongTask,0,"FSim2 Song",Fs);

 //$FG,2$Attr gets set by ltf, so make sure done with update before setting.$FG$
 WinSync;
 Fs->update_win=&UpdateWin;
 //Set callback for irregular aborts (kill or CTRL-ALT-X)
 Fs->end_task_cb=&EndTaskCB;

 //$FG,2$This heap is uncached$FG$
 Fs->mp=mp=MAllocHCZ(sizeof(MPCtrl),mp_heap);
 mp->win_tss=Fs;
 mp->base=GrAlias(cpu_cached[1].grbase,Fs);
//$FG,2$CPU 1 heap is too small for depth buffer allocation$FG$
 GrAllocDepthBuffer(mp->base);
 WbInvd; //Write mp out of cache

 if (mp_cnt>1)
     MPSpawn(&MPUpdateTask,mp,"FSim2",1<<1);

 try //$FG,2$in case CTRL-ALT-C is pressed.$FG$
     do {
             ch=GetKey(&sc);
             pp=phi; tt1=theta1; tt2=theta2;
             switch (ch) {
                 case 0:
                     switch (sc.u1[0]) {
                         case SC_CURSOR_DOWN:
                             phi   +=-CONTROLS_SCALE*Cos(tt1);
                             theta2+=-CONTROLS_SCALE*Sin(tt1)*Sin(phi);
                             break;
                         case SC_CURSOR_UP:
                             phi   -=-CONTROLS_SCALE*Cos(tt1);
                             theta2-=-CONTROLS_SCALE*Sin(tt1)*Sin(phi);
                             break;
                         case SC_CURSOR_RIGHT:
                             theta1+=CONTROLS_SCALE;
                             break;
                         case SC_CURSOR_LEFT:
                             theta1-=CONTROLS_SCALE;
                             break;
                     }
                     break;
             }
             theta1=Unwrap(theta1);
             phi   =Unwrap(phi);
             theta2=Unwrap(theta2);
         } while (ch!=CH_CTRLQ && ch!=CH_ESC);
         catch
     Fs->catch_except=TRUE;

 Kill(animate_tss);
 Kill(song_tss);
 Sound(0);
 Fs->update_win=old_update;
 Fs->end_task_cb=NULL;
 WordStat(old_wordstat);
 win_max_refresh=old_refresh;
 Sound(0);
 Fs->text_attr=old_attr;

 MPEnd(mp);
 Fs->mp=NULL;
 GrDel(mp->base);
 PanelsDel;
}

FlightSim2;
...................B...øÿÿÿB...L......H...øÿÿÿH...L......N...øÿÿÿN...L......T...øÿÿÿT...L......Z...
øÿÿÿZ...L......`...øÿÿÿ`...L......f...øÿÿÿf...L......l...øÿÿÿl...L......r...øÿÿÿr...L......x...øÿÿÿx...
L......~...øÿÿÿ~...L......„...øÿÿÿ„...L......B...øÿÿÿ„...øÿÿÿ...B...þÿÿÿ„...þÿÿÿ...B......„.........B...
...„...
......B......„.........B......„.........B......„.........B..."...„..."......B...(...„...(......
B.......„..........B...4...„...4......B...:...„...:......B...@...„...@......B...F...„...F......B...L...„...
L............
...]...        ...m.........`......o.........`......p.........c......r......... ...f...
ûÿÿÿx.........l...÷ÿÿÿ~...        ......h...úÿÿÿ|...
Home

Flight Simulator
FirstPersonShootr
BigGuns
BirdLand
MultiCore
Tanks
TimeOut
X-Caliber